Browse Source

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
pull/1/head
Juergen Hoeller 17 years ago
parent
commit
d7836b9fcc
  1. 175
      org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

175
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. * Class representing injection information about an annotated field.
@ -419,39 +436,37 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
try { try {
Object value; Object value;
if (this.cached) { if (this.cached) {
if (this.cachedFieldValue instanceof DependencyDescriptor) { value = resolvedCachedArgument(beanName, this.cachedFieldValue);
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;
}
} }
else { else {
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1); synchronized (this) {
TypeConverter typeConverter = beanFactory.getTypeConverter(); if (!this.cached) {
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required); Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
this.cachedFieldValue = descriptor; TypeConverter typeConverter = beanFactory.getTypeConverter();
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter); DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
if (value != null) { this.cachedFieldValue = descriptor;
registerDependentBeans(beanName, autowiredBeanNames); value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
if (autowiredBeanNames.size() == 1) { if (value != null) {
String autowiredBeanName = autowiredBeanNames.iterator().next(); registerDependentBeans(beanName, autowiredBeanNames);
if (beanFactory.containsBean(autowiredBeanName)) { if (autowiredBeanNames.size() == 1) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { String autowiredBeanName = autowiredBeanNames.iterator().next();
this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName); 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) { if (value != null) {
ReflectionUtils.makeAccessible(field); ReflectionUtils.makeAccessible(field);
@ -492,65 +507,58 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
} }
Method method = (Method) this.member; Method method = (Method) this.member;
try { try {
Object[] arguments = null; Object[] arguments;
if (this.cached) { if (this.cached) {
if (this.cachedMethodArguments != null) { // Shortcut for avoiding synchronization...
arguments = new Object[this.cachedMethodArguments.length]; arguments = resolveCachedArguments(beanName);
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;
}
}
}
} }
else { else {
Class[] paramTypes = method.getParameterTypes(); synchronized (this) {
arguments = new Object[paramTypes.length]; if (!this.cached) {
Set<String> autowiredBeanNames = new LinkedHashSet<String>(arguments.length); Class[] paramTypes = method.getParameterTypes();
TypeConverter typeConverter = beanFactory.getTypeConverter(); arguments = new Object[paramTypes.length];
this.cachedMethodArguments = new Object[arguments.length]; Set<String> autowiredBeanNames = new LinkedHashSet<String>(arguments.length);
for (int i = 0; i < arguments.length; i++) { TypeConverter typeConverter = beanFactory.getTypeConverter();
MethodParameter methodParam = new MethodParameter(method, i); this.cachedMethodArguments = new Object[arguments.length];
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass()); for (int i = 0; i < arguments.length; i++) {
DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required); MethodParameter methodParam = new MethodParameter(method, i);
this.cachedMethodArguments[i] = descriptor; GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
arguments[i] = beanFactory.resolveDependency( DependencyDescriptor descriptor = new DependencyDescriptor(methodParam, this.required);
descriptor, beanName, autowiredBeanNames, typeConverter); this.cachedMethodArguments[i] = descriptor;
if (arguments[i] == null) { arguments[i] = beanFactory.resolveDependency(
arguments = null; descriptor, beanName, autowiredBeanNames, typeConverter);
break; if (arguments[i] == null) {
} arguments = null;
} break;
if (arguments != null) {
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == paramTypes.length) {
Iterator<String> 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]; if (arguments != null) {
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == paramTypes.length) {
Iterator<String> 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.skip == null) {
if (this.pd != null && pvs instanceof MutablePropertyValues) { 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); 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;
}
} }
} }

Loading…
Cancel
Save