From d7836b9fcc3ec3aa3a6a3e9481d3d82047a70dce Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 27 Apr 2009 22:53:40 +0000 Subject: [PATCH] fixed potential race condition through additional synchronization (SPR-5658) git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1069 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../AutowiredAnnotationBeanPostProcessor.java | 177 ++++++++++-------- 1 file changed, 98 insertions(+), 79 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 2a641819468..d60a75cec78 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -396,6 +396,23 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean } } + /** + * Resolve the specified cached method argument or field value. + */ + private Object resolvedCachedArgument(String beanName, Object cachedArgument) { + if (cachedArgument instanceof DependencyDescriptor) { + DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument; + TypeConverter typeConverter = beanFactory.getTypeConverter(); + return beanFactory.resolveDependency(descriptor, beanName, null, typeConverter); + } + else if (cachedArgument instanceof RuntimeBeanReference) { + return beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName()); + } + else { + return cachedArgument; + } + } + /** * Class representing injection information about an annotated field. @@ -419,39 +436,37 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean try { Object value; if (this.cached) { - if (this.cachedFieldValue instanceof DependencyDescriptor) { - DependencyDescriptor descriptor = (DependencyDescriptor) this.cachedFieldValue; - TypeConverter typeConverter = beanFactory.getTypeConverter(); - value = beanFactory.resolveDependency(descriptor, beanName, null, typeConverter); - } - else if (this.cachedFieldValue instanceof RuntimeBeanReference) { - value = beanFactory.getBean(((RuntimeBeanReference) this.cachedFieldValue).getBeanName()); - } - else { - value = this.cachedFieldValue; - } + value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { - Set autowiredBeanNames = new LinkedHashSet(1); - TypeConverter typeConverter = beanFactory.getTypeConverter(); - DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required); - this.cachedFieldValue = descriptor; - value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter); - if (value != null) { - registerDependentBeans(beanName, autowiredBeanNames); - if (autowiredBeanNames.size() == 1) { - String autowiredBeanName = autowiredBeanNames.iterator().next(); - if (beanFactory.containsBean(autowiredBeanName)) { - if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { - this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName); + synchronized (this) { + if (!this.cached) { + Set autowiredBeanNames = new LinkedHashSet(1); + TypeConverter typeConverter = beanFactory.getTypeConverter(); + DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required); + this.cachedFieldValue = descriptor; + value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter); + if (value != null) { + registerDependentBeans(beanName, autowiredBeanNames); + if (autowiredBeanNames.size() == 1) { + String autowiredBeanName = autowiredBeanNames.iterator().next(); + if (beanFactory.containsBean(autowiredBeanName)) { + if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { + this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName); + } + } } } + else { + this.cachedFieldValue = null; + } + this.cached = true; + } + else { + // Already cached in the meantime... + value = resolvedCachedArgument(beanName, this.cachedFieldValue); } } - else { - this.cachedFieldValue = null; - } - this.cached = true; } if (value != null) { ReflectionUtils.makeAccessible(field); @@ -492,65 +507,58 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean } Method method = (Method) this.member; try { - Object[] arguments = null; + Object[] arguments; if (this.cached) { - if (this.cachedMethodArguments != null) { - arguments = new Object[this.cachedMethodArguments.length]; - for (int i = 0; i < arguments.length; i++) { - Object cachedArg = this.cachedMethodArguments[i]; - if (cachedArg instanceof DependencyDescriptor) { - DependencyDescriptor descriptor = (DependencyDescriptor) cachedArg; - TypeConverter typeConverter = beanFactory.getTypeConverter(); - arguments[i] = beanFactory.resolveDependency(descriptor, beanName, null, typeConverter); - } - else if (cachedArg instanceof RuntimeBeanReference) { - arguments[i] = beanFactory.getBean(((RuntimeBeanReference) cachedArg).getBeanName()); - } - else { - arguments[i] = cachedArg; - } - } - } + // Shortcut for avoiding synchronization... + arguments = resolveCachedArguments(beanName); } else { - Class[] paramTypes = method.getParameterTypes(); - arguments = new Object[paramTypes.length]; - Set autowiredBeanNames = new LinkedHashSet(arguments.length); - TypeConverter typeConverter = beanFactory.getTypeConverter(); - this.cachedMethodArguments = new Object[arguments.length]; - for (int i = 0; i < arguments.length; i++) { - MethodParameter methodParam = new MethodParameter(method, i); - GenericTypeResolver.resolveParameterType(methodParam, bean.getClass()); - DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required); - this.cachedMethodArguments[i] = descriptor; - arguments[i] = beanFactory.resolveDependency( - descriptor, beanName, autowiredBeanNames, typeConverter); - if (arguments[i] == null) { - arguments = null; - break; - } - } - if (arguments != null) { - registerDependentBeans(beanName, autowiredBeanNames); - if (autowiredBeanNames.size() == paramTypes.length) { - Iterator it = autowiredBeanNames.iterator(); - for (int i = 0; i < paramTypes.length; i++) { - String autowiredBeanName = it.next(); - if (beanFactory.containsBean(autowiredBeanName)) { - if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { - this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName); - } - } - else { - this.cachedMethodArguments[i] = arguments[i]; + synchronized (this) { + if (!this.cached) { + Class[] paramTypes = method.getParameterTypes(); + arguments = new Object[paramTypes.length]; + Set autowiredBeanNames = new LinkedHashSet(arguments.length); + TypeConverter typeConverter = beanFactory.getTypeConverter(); + this.cachedMethodArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + MethodParameter methodParam = new MethodParameter(method, i); + GenericTypeResolver.resolveParameterType(methodParam, bean.getClass()); + DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required); + this.cachedMethodArguments[i] = descriptor; + arguments[i] = beanFactory.resolveDependency( + descriptor, beanName, autowiredBeanNames, typeConverter); + if (arguments[i] == null) { + arguments = null; + break; } } + if (arguments != null) { + registerDependentBeans(beanName, autowiredBeanNames); + if (autowiredBeanNames.size() == paramTypes.length) { + Iterator it = autowiredBeanNames.iterator(); + for (int i = 0; i < paramTypes.length; i++) { + String autowiredBeanName = it.next(); + if (beanFactory.containsBean(autowiredBeanName)) { + if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { + this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName); + } + } + else { + this.cachedMethodArguments[i] = arguments[i]; + } + } + } + } + else { + this.cachedMethodArguments = null; + } + this.cached = true; + } + else { + // Already cached in the meantime... + arguments = resolveCachedArguments(beanName); } } - else { - this.cachedMethodArguments = null; - } - this.cached = true; } if (this.skip == null) { if (this.pd != null && pvs instanceof MutablePropertyValues) { @@ -570,6 +578,17 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean throw new BeanCreationException("Could not autowire method: " + method, ex); } } + + private Object[] resolveCachedArguments(String beanName) { + if (this.cachedMethodArguments == null) { + return null; + } + Object[] arguments = new Object[this.cachedMethodArguments.length]; + for (int i = 0; i < arguments.length; i++) { + arguments[i] = resolvedCachedArgument(beanName, this.cachedMethodArguments[i]); + } + return arguments; + } } }