Skip to content

Commit b6ef3cf

Browse files
committed
Refactor HandlerExecutionChain towards List-centric interceptor storage
Closes gh-25500
1 parent d61c0ee commit b6ef3cf

12 files changed

+162
-188
lines changed
Lines changed: 69 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
1717
package org.springframework.web.servlet;
1818

1919
import java.util.ArrayList;
20+
import java.util.Arrays;
21+
import java.util.Collections;
2022
import java.util.List;
2123

2224
import javax.servlet.http.HttpServletRequest;
@@ -27,7 +29,6 @@
2729

2830
import org.springframework.lang.Nullable;
2931
import org.springframework.util.CollectionUtils;
30-
import org.springframework.util.ObjectUtils;
3132

3233
/**
3334
* Handler execution chain, consisting of handler object and any handler interceptors.
@@ -43,11 +44,7 @@ public class HandlerExecutionChain {
4344

4445
private final Object handler;
4546

46-
@Nullable
47-
private HandlerInterceptor[] interceptors;
48-
49-
@Nullable
50-
private List<HandlerInterceptor> interceptorList;
47+
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
5148

5249
private int interceptorIndex = -1;
5350

@@ -67,17 +64,26 @@ public HandlerExecutionChain(Object handler) {
6764
* (in the given order) before the handler itself executes
6865
*/
6966
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
67+
this(handler, (interceptors != null ? Arrays.asList(interceptors) : Collections.emptyList()));
68+
}
69+
70+
/**
71+
* Create a new HandlerExecutionChain.
72+
* @param handler the handler object to execute
73+
* @param interceptorList the list of interceptors to apply
74+
* (in the given order) before the handler itself executes
75+
* @since 5.3
76+
*/
77+
public HandlerExecutionChain(Object handler, List<HandlerInterceptor> interceptorList) {
7078
if (handler instanceof HandlerExecutionChain) {
7179
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
7280
this.handler = originalChain.getHandler();
73-
this.interceptorList = new ArrayList<>();
74-
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
75-
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
81+
this.interceptorList.addAll(originalChain.interceptorList);
7682
}
7783
else {
7884
this.handler = handler;
79-
this.interceptors = interceptors;
8085
}
86+
this.interceptorList.addAll(interceptorList);
8187
}
8288

8389

@@ -88,30 +94,25 @@ public Object getHandler() {
8894
return this.handler;
8995
}
9096

97+
/**
98+
* Add the given interceptor to the end of this chain.
99+
*/
91100
public void addInterceptor(HandlerInterceptor interceptor) {
92-
initInterceptorList().add(interceptor);
101+
this.interceptorList.add(interceptor);
93102
}
94103

104+
/**
105+
* Add the given interceptor at the specified index of this chain.
106+
*/
95107
public void addInterceptor(int index, HandlerInterceptor interceptor) {
96-
initInterceptorList().add(index, interceptor);
108+
this.interceptorList.add(index, interceptor);
97109
}
98110

111+
/**
112+
* Add the given interceptors to the end of this chain.
113+
*/
99114
public void addInterceptors(HandlerInterceptor... interceptors) {
100-
if (!ObjectUtils.isEmpty(interceptors)) {
101-
CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());
102-
}
103-
}
104-
105-
private List<HandlerInterceptor> initInterceptorList() {
106-
if (this.interceptorList == null) {
107-
this.interceptorList = new ArrayList<>();
108-
if (this.interceptors != null) {
109-
// An interceptor array specified through the constructor
110-
CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
111-
}
112-
}
113-
this.interceptors = null;
114-
return this.interceptorList;
115+
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
115116
}
116117

117118
/**
@@ -120,10 +121,17 @@ private List<HandlerInterceptor> initInterceptorList() {
120121
*/
121122
@Nullable
122123
public HandlerInterceptor[] getInterceptors() {
123-
if (this.interceptors == null && this.interceptorList != null) {
124-
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
125-
}
126-
return this.interceptors;
124+
return (!this.interceptorList.isEmpty() ? this.interceptorList.toArray(new HandlerInterceptor[0]) : null);
125+
}
126+
127+
/**
128+
* Return the list of interceptors to apply (in the given order).
129+
* @return the list of HandlerInterceptors instances (potentially empty)
130+
* @since 5.3
131+
*/
132+
public List<HandlerInterceptor> getInterceptorList() {
133+
return (!this.interceptorList.isEmpty() ? Collections.unmodifiableList(this.interceptorList) :
134+
Collections.emptyList());
127135
}
128136

129137

@@ -134,16 +142,13 @@ public HandlerInterceptor[] getInterceptors() {
134142
* that this interceptor has already dealt with the response itself.
135143
*/
136144
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
137-
HandlerInterceptor[] interceptors = getInterceptors();
138-
if (!ObjectUtils.isEmpty(interceptors)) {
139-
for (int i = 0; i < interceptors.length; i++) {
140-
HandlerInterceptor interceptor = interceptors[i];
141-
if (!interceptor.preHandle(request, response, this.handler)) {
142-
triggerAfterCompletion(request, response, null);
143-
return false;
144-
}
145-
this.interceptorIndex = i;
145+
for (int i = 0; i < this.interceptorList.size(); i++) {
146+
HandlerInterceptor interceptor = this.interceptorList.get(i);
147+
if (!interceptor.preHandle(request, response, this.handler)) {
148+
triggerAfterCompletion(request, response, null);
149+
return false;
146150
}
151+
this.interceptorIndex = i;
147152
}
148153
return true;
149154
}
@@ -154,12 +159,9 @@ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)
154159
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
155160
throws Exception {
156161

157-
HandlerInterceptor[] interceptors = getInterceptors();
158-
if (!ObjectUtils.isEmpty(interceptors)) {
159-
for (int i = interceptors.length - 1; i >= 0; i--) {
160-
HandlerInterceptor interceptor = interceptors[i];
161-
interceptor.postHandle(request, response, this.handler, mv);
162-
}
162+
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
163+
HandlerInterceptor interceptor = this.interceptorList.get(i);
164+
interceptor.postHandle(request, response, this.handler, mv);
163165
}
164166
}
165167

@@ -168,19 +170,14 @@ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @
168170
* Will just invoke afterCompletion for all interceptors whose preHandle invocation
169171
* has successfully completed and returned true.
170172
*/
171-
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
172-
throws Exception {
173-
174-
HandlerInterceptor[] interceptors = getInterceptors();
175-
if (!ObjectUtils.isEmpty(interceptors)) {
176-
for (int i = this.interceptorIndex; i >= 0; i--) {
177-
HandlerInterceptor interceptor = interceptors[i];
178-
try {
179-
interceptor.afterCompletion(request, response, this.handler, ex);
180-
}
181-
catch (Throwable ex2) {
182-
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
183-
}
173+
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
174+
for (int i = this.interceptorIndex; i >= 0; i--) {
175+
HandlerInterceptor interceptor = this.interceptorList.get(i);
176+
try {
177+
interceptor.afterCompletion(request, response, this.handler, ex);
178+
}
179+
catch (Throwable ex2) {
180+
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
184181
}
185182
}
186183
}
@@ -189,16 +186,16 @@ void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse resp
189186
* Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
190187
*/
191188
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
192-
HandlerInterceptor[] interceptors = getInterceptors();
193-
if (!ObjectUtils.isEmpty(interceptors)) {
194-
for (int i = interceptors.length - 1; i >= 0; i--) {
195-
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
196-
try {
197-
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
198-
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
199-
}
200-
catch (Throwable ex) {
201-
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
189+
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
190+
HandlerInterceptor interceptor = this.interceptorList.get(i);
191+
if (interceptor instanceof AsyncHandlerInterceptor) {
192+
try {
193+
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptor;
194+
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
195+
}
196+
catch (Throwable ex) {
197+
if (logger.isErrorEnabled()) {
198+
logger.error("Interceptor [" + interceptor + "] failed in afterConcurrentHandlingStarted", ex);
202199
}
203200
}
204201
}
@@ -207,23 +204,11 @@ void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServlet
207204

208205

209206
/**
210-
* Delegates to the handler and interceptors' {@code toString()}.
207+
* Delegates to the handler's {@code toString()} implementation.
211208
*/
212209
@Override
213210
public String toString() {
214-
Object handler = getHandler();
215-
StringBuilder sb = new StringBuilder();
216-
sb.append("HandlerExecutionChain with [").append(handler).append("] and ");
217-
if (this.interceptorList != null) {
218-
sb.append(this.interceptorList.size());
219-
}
220-
else if (this.interceptors != null) {
221-
sb.append(this.interceptors.length);
222-
}
223-
else {
224-
sb.append(0);
225-
}
226-
return sb.append(" interceptors").toString();
211+
return "HandlerExecutionChain with [" + getHandler() + "] and " + this.interceptorList.size() + " interceptors";
227212
}
228213

229214
}

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,13 +652,13 @@ protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest
652652
HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
653653

654654
if (CorsUtils.isPreFlightRequest(request)) {
655-
HandlerInterceptor[] interceptors = chain.getInterceptors();
656-
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
655+
List<HandlerInterceptor> interceptors = chain.getInterceptorList();
656+
return new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
657657
}
658658
else {
659659
chain.addInterceptor(0, new CorsInterceptor(config));
660+
return chain;
660661
}
661-
return chain;
662662
}
663663

664664

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,9 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
169169
if (handler == null) {
170170
continue;
171171
}
172-
if (handler.getInterceptors() != null) {
173-
for (HandlerInterceptor interceptor : handler.getInterceptors()) {
174-
if (interceptor instanceof CorsConfigurationSource) {
175-
return ((CorsConfigurationSource) interceptor).getCorsConfiguration(wrapper);
176-
}
172+
for (HandlerInterceptor interceptor : handler.getInterceptorList()) {
173+
if (interceptor instanceof CorsConfigurationSource) {
174+
return ((CorsConfigurationSource) interceptor).getCorsConfiguration(wrapper);
177175
}
178176
}
179177
if (handler.getHandler() instanceof CorsConfigurationSource) {

spring-webmvc/src/test/java/org/springframework/web/servlet/HandlerExecutionChainTests.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -65,9 +65,7 @@ public void setup() {
6565

6666
this.chain.addInterceptor(this.interceptor1);
6767
this.chain.addInterceptor(this.interceptor2);
68-
assertThat(this.chain.getInterceptors().length).isEqualTo(2);
6968
this.chain.addInterceptor(this.interceptor3);
70-
assertThat(this.chain.getInterceptors().length).isEqualTo(3);
7169
}
7270

7371

0 commit comments

Comments
 (0)