Introduced support for @Lazy on injection points

This turned into a rather huge affair since it led to the introduction of a new AutowireCandidateResolver implementation in the spring-context module. That ACR impl is now being set through AnnotationConfigUtils; GenericApplicationContext and co do not set a default QualifierAnnotationAutowireCandidateResolver anymore (which has always been a smell anyway).  At the same time, dependency ordering has moved from AutowiredAnnotationBeanPostProcessor to DefaultListableBeanFactory itself through a "dependencyComparator" strategy, applying to constructor dependencies and lazy resolution proxies as well.

Issue: SPR-10353
This commit is contained in:
Juergen Hoeller
2013-08-28 00:14:39 +02:00
parent 01b8d9327d
commit 4447248a83
16 changed files with 554 additions and 49 deletions

View File

@@ -57,7 +57,6 @@ import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -436,10 +435,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private Object resolvedCachedArgument(String beanName, Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
TypeConverter typeConverter = this.beanFactory.getTypeConverter();
Object value = this.beanFactory.resolveDependency(descriptor, beanName, null, typeConverter);
AnnotationAwareOrderComparator.sortIfNecessary(value);
return value;
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
}
else if (cachedArgument instanceof RuntimeBeanReference) {
return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
@@ -479,7 +475,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
AnnotationAwareOrderComparator.sortIfNecessary(value);
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
@@ -557,7 +552,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
arguments = null;
break;
}
AnnotationAwareOrderComparator.sortIfNecessary(arg);
arguments[i] = arg;
}
synchronized (this) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -131,6 +131,10 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
this.beanFactory = beanFactory;
}
protected final BeanFactory getBeanFactory() {
return this.beanFactory;
}
/**
* Determine whether the provided bean definition is an autowire candidate.
@@ -336,4 +340,14 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
return value;
}
/**
* This implementation always returns {@code null},
* leaving lazy resolution support up to subclasses.
*/
@Override
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,8 @@ import org.springframework.beans.factory.config.DependencyDescriptor;
* Strategy interface for determining whether a specific bean definition
* qualifies as an autowire candidate for a specific dependency.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @author Mark Fisher
* @since 2.5
*/
public interface AutowireCandidateResolver {
@@ -47,4 +47,15 @@ public interface AutowireCandidateResolver {
*/
Object getSuggestedValue(DependencyDescriptor descriptor);
/**
* Build a proxy for lazy resolution of the actual dependency target,
* if demanded by the injection point.
* @param descriptor the descriptor for the target method parameter or field
* @param beanName the name of the bean that contains the injection point
* @return the lazy resolution proxy for the actual dependency target,
* or {@code null} if straight resolution is to be performed
* @since 4.0
*/
Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName);
}

View File

@@ -29,6 +29,8 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
@@ -125,6 +127,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** Optional OrderComparator for dependency Lists and arrays */
private Comparator dependencyComparator;
/** Resolver to use for checking if a bean definition is an autowire candidate */
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
@@ -205,6 +210,22 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
this.allowEagerClassLoading = allowEagerClassLoading;
}
/**
* Set a {@link java.util.Comparator} for dependency Lists and arrays.
* @see org.springframework.core.OrderComparator
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
*/
public void setDependencyComparator(Comparator dependencyComparator) {
this.dependencyComparator = dependencyComparator;
}
/**
* Return the dependency comparator for this BeanFactory (may be {@code null}.
*/
public Comparator getDependencyComparator() {
return this.dependencyComparator;
}
/**
* Set a custom autowire candidate resolver for this BeanFactory to use
* when deciding whether a bean definition should be considered as a
@@ -786,13 +807,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
}
else {
return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, beanName);
if (result == null) {
result = doResolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
@@ -819,7 +845,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return converter.convertIfNecessary(matchingBeans.values(), type);
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (this.dependencyComparator != null && result instanceof Object[]) {
Arrays.sort((Object[]) result, this.dependencyComparator);
}
return result;
}
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getCollectionType();
@@ -840,7 +870,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return converter.convertIfNecessary(matchingBeans.values(), type);
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (this.dependencyComparator != null && result instanceof List) {
Collections.sort((List) result, this.dependencyComparator);
}
return result;
}
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> keyType = descriptor.getMapKeyType();
@@ -1091,7 +1125,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public Object getObject() throws BeansException {
return doResolveDependency(this.descriptor, this.descriptor.getDependencyType(), this.beanName, null, null);
return doResolveDependency(this.descriptor, this.beanName, null, null);
}
}

View File

@@ -1,6 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,4 +46,9 @@ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolve
return null;
}
@Override
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
return null;
}
}