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:
@@ -26,8 +26,11 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -35,14 +38,16 @@ import org.springframework.util.ClassUtils;
|
||||
* Utility class that allows for convenient registration of common
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor} and
|
||||
* {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor}
|
||||
* definitions for annotation-based configuration.
|
||||
* definitions for annotation-based configuration. Also registers a common
|
||||
* {@link org.springframework.beans.factory.support.AutowireCandidateResolver}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @since 2.5
|
||||
* @see ContextAnnotationAutowireCandidateResolver
|
||||
* @see CommonAnnotationBeanPostProcessor
|
||||
* @see org.springframework.context.annotation.ConfigurationClassPostProcessor
|
||||
* @see ConfigurationClassPostProcessor
|
||||
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
|
||||
* @see org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
|
||||
* @see org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
|
||||
@@ -176,6 +181,16 @@ public class AnnotationConfigUtils {
|
||||
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
|
||||
BeanDefinitionRegistry registry, Object source) {
|
||||
|
||||
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
|
||||
if (beanFactory != null) {
|
||||
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
|
||||
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
|
||||
}
|
||||
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
|
||||
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
|
||||
}
|
||||
}
|
||||
|
||||
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
|
||||
|
||||
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
|
||||
@@ -229,6 +244,18 @@ public class AnnotationConfigUtils {
|
||||
return new BeanDefinitionHolder(definition, beanName);
|
||||
}
|
||||
|
||||
private static DefaultListableBeanFactory unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry) {
|
||||
if (registry instanceof DefaultListableBeanFactory) {
|
||||
return (DefaultListableBeanFactory) registry;
|
||||
}
|
||||
else if (registry instanceof GenericApplicationContext) {
|
||||
return ((GenericApplicationContext) registry).getDefaultListableBeanFactory();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
|
||||
processCommonDefinitionAnnotations(abd, abd.getMetadata());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.context.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Complete implementation of the {@link org.springframework.beans.factory.support.AutowireCandidateResolver}
|
||||
* strategy interface, providing support for qualifier annotations as well as for lazy resolution driven
|
||||
* by the {@link Lazy} annotation in the {@code context.annotation} package.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
*/
|
||||
public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver {
|
||||
|
||||
@Override
|
||||
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
|
||||
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
|
||||
}
|
||||
|
||||
protected boolean isLazy(DependencyDescriptor descriptor) {
|
||||
for (Annotation ann : descriptor.getAnnotations()) {
|
||||
Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
|
||||
if (lazy != null && lazy.value()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
MethodParameter methodParam = descriptor.getMethodParameter();
|
||||
if (methodParam != null) {
|
||||
Method method = methodParam.getMethod();
|
||||
if (method == null || void.class.equals(method.getReturnType())) {
|
||||
Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
|
||||
if (lazy != null && lazy.value()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final String beanName) {
|
||||
Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory,
|
||||
"BeanFactory needs to be a DefaultListableBeanFactory");
|
||||
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory();
|
||||
TargetSource ts = new TargetSource() {
|
||||
@Override
|
||||
public Class<?> getTargetClass() {
|
||||
return descriptor.getDependencyType();
|
||||
}
|
||||
@Override
|
||||
public boolean isStatic() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
return beanFactory.doResolveDependency(descriptor, beanName, null, null);
|
||||
}
|
||||
@Override
|
||||
public void releaseTarget(Object target) {
|
||||
}
|
||||
};
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.setTargetSource(ts);
|
||||
Class<?> dependencyType = descriptor.getDependencyType();
|
||||
if (dependencyType.isInterface()) {
|
||||
pf.addInterface(dependencyType);
|
||||
}
|
||||
return pf.getProxy(beanFactory.getBeanClassLoader());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
@@ -42,14 +42,21 @@ import java.lang.annotation.Target;
|
||||
* method within a {@code @Lazy}-annotated {@code @Configuration} class, this indicates
|
||||
* overriding the 'default lazy' behavior and that the bean should be eagerly initialized.
|
||||
*
|
||||
* <p>In addition to its role for component initialization, this annotation may also be placed
|
||||
* on injection points marked with {@link org.springframework.beans.factory.annotation.Autowired}
|
||||
* or {@link javax.inject.Inject}: In that context, it leads to the creation of a
|
||||
* lazy-resolution proxy for all affected dependencies, as an alternative to using
|
||||
* {@link org.springframework.beans.factory.ObjectFactory} or {@link javax.inject.Provider}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see Primary
|
||||
* @see Bean
|
||||
* @see Configuration
|
||||
* @see org.springframework.stereotype.Component
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Lazy {
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.context.support;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -222,7 +221,6 @@ public abstract class AbstractRefreshableApplicationContext extends AbstractAppl
|
||||
if (this.allowCircularReferences != null) {
|
||||
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
|
||||
}
|
||||
beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
@@ -21,7 +21,6 @@ import java.io.IOException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
@@ -100,7 +99,6 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
|
||||
*/
|
||||
public GenericApplicationContext() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
this.beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user