Permalink
Browse files

Make the methodParameter field of HandlerMethod final

Previously the methodParameter array field was initialized lazily since
it requires reflection. However, in practice the field is always used
and there is not much benefit from the lazy initialization.

In Spring Framework 3.2, the methodParameter field was copied when a
new HandlerMethod instance (with the resolved bean) is created for
performance reasons. That introduced a synchronization issue since
the lazy initialization was not synchronized.

Issue: SPR-10365
  • Loading branch information...
1 parent 3654a62 commit 8ab8e4f7c2023df3486cdc256fbab09bb1aae73e @rstoyanchev rstoyanchev committed Mar 10, 2013
Showing with 28 additions and 12 deletions.
  1. +28 −12 spring-web/src/main/java/org/springframework/web/method/HandlerMethod.java
@@ -54,7 +54,7 @@
private final BeanFactory beanFactory;
- private MethodParameter[] parameters;
+ private final MethodParameter[] parameters;
private final Method bridgedMethod;
@@ -69,6 +69,16 @@ public HandlerMethod(Object bean, Method method) {
this.beanFactory = null;
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
+ this.parameters = initMethodParameters();
+ }
+
+ private MethodParameter[] initMethodParameters() {
+ int count = this.bridgedMethod.getParameterTypes().length;
+ MethodParameter[] result = new MethodParameter[count];
+ for (int i = 0; i < count; i++) {
+ result[i] = new HandlerMethodParameter(i);
+ }
+ return result;
}
/**
@@ -82,6 +92,7 @@ public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes)
this.beanFactory = null;
this.method = bean.getClass().getMethod(methodName, parameterTypes);
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
+ this.parameters = initMethodParameters();
}
/**
@@ -99,10 +110,11 @@ public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
this.beanFactory = beanFactory;
this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
+ this.parameters = initMethodParameters();
}
/**
- * Create an instance from another {@code HandlerMethod}.
+ * Copy constructor for use in sub-classes.
*/
protected HandlerMethod(HandlerMethod handlerMethod) {
Assert.notNull(handlerMethod, "HandlerMethod is required");
@@ -113,6 +125,19 @@ protected HandlerMethod(HandlerMethod handlerMethod) {
this.parameters = handlerMethod.parameters;
}
+ /**
+ * Re-create HandlerMethod with the resolved handler.
+ */
+ private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
+ Assert.notNull(handlerMethod, "handlerMethod is required");
+ Assert.notNull(handler, "handler is required");
+ this.bean = handler;
+ this.beanFactory = handlerMethod.beanFactory;
+ this.method = handlerMethod.method;
+ this.bridgedMethod = handlerMethod.bridgedMethod;
+ this.parameters = handlerMethod.parameters;
+ }
+
/**
* Returns the bean for this handler method.
*/
@@ -150,13 +175,6 @@ protected Method getBridgedMethod() {
* Returns the method parameters for this handler method.
*/
public MethodParameter[] getMethodParameters() {
- if (this.parameters == null) {
- int parameterCount = this.bridgedMethod.getParameterTypes().length;
- this.parameters = new MethodParameter[parameterCount];
- for (int i = 0; i < parameterCount; i++) {
- this.parameters[i] = new HandlerMethodParameter(i);
- }
- }
return this.parameters;
}
@@ -201,9 +219,7 @@ public HandlerMethod createWithResolvedBean() {
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
- HandlerMethod handlerMethod = new HandlerMethod(handler, this.method);
- handlerMethod.parameters = getMethodParameters();
- return handlerMethod;
+ return new HandlerMethod(this, handler);
}
@Override

0 comments on commit 8ab8e4f

Please sign in to comment.