diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java index bb1740e3972d..0a1f0a7d6910 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2020 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. @@ -16,6 +16,7 @@ package org.springframework.beans.factory.support; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.lang.Nullable; @@ -99,4 +100,22 @@ default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor return null; } + /** + * Return a clone of this resolver instance if necessary, retaining its local + * configuration and allowing for the cloned instance to get associated with + * a new bean factory, or this original instance if there is no such state. + *

The default implementation creates a separate instance via the default + * class constructor, assuming no specific configuration state to copy. + * Subclasses may override this with custom configuration state handling + * or with standard {@link Cloneable} support (as implemented by Spring's + * own configurable {@code AutowireCandidateResolver} variants), or simply + * return {@code this} (as in {@link SimpleAutowireCandidateResolver}). + * @since 5.2.7 + * @see GenericTypeAwareAutowireCandidateResolver#cloneIfNecessary() + * @see DefaultListableBeanFactory#copyConfigurationFrom + */ + default AutowireCandidateResolver cloneIfNecessary() { + return BeanUtils.instantiateClass(getClass()); + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 3bffd264e2f2..c9bd992ded5e 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -46,7 +46,6 @@ import javax.inject.Provider; -import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.BeanCreationException; @@ -157,7 +156,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto private Comparator dependencyComparator; /** Resolver to use for checking if a bean definition is an autowire candidate. */ - private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver(); + private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE; /** Map from dependency type to corresponding autowired value. */ private final Map, Object> resolvableDependencies = new ConcurrentHashMap<>(16); @@ -328,8 +327,7 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading; this.dependencyComparator = otherListableFactory.dependencyComparator; // A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware... - setAutowireCandidateResolver( - BeanUtils.instantiateClass(otherListableFactory.getAutowireCandidateResolver().getClass())); + setAutowireCandidateResolver(otherListableFactory.getAutowireCandidateResolver().cloneIfNecessary()); // Make resolvable dependencies (e.g. ResourceLoader) available here as well... this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java index 7143fc9b1fa1..01b81450903d 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 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. @@ -43,7 +43,7 @@ * @since 4.0 */ public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver - implements BeanFactoryAware { + implements BeanFactoryAware, Cloneable { @Nullable private BeanFactory beanFactory; @@ -177,4 +177,21 @@ protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, D return null; } + + /** + * This implementation clones all instance fields through standard + * {@link Cloneable} support, allowing for subsequent reconfiguration + * of the cloned instance through a fresh {@link #setBeanFactory} call. + * @see #clone() + */ + @Override + public AutowireCandidateResolver cloneIfNecessary() { + try { + return (AutowireCandidateResolver) clone(); + } + catch (CloneNotSupportedException ex) { + throw new IllegalStateException(ex); + } + } + } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java index 17909b5946b9..f33eeecf16aa 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2020 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. @@ -30,6 +30,13 @@ */ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolver { + /** + * Shared instance of {@code SimpleAutowireCandidateResolver}. + * @since 5.2.7 + */ + public static final SimpleAutowireCandidateResolver INSTANCE = new SimpleAutowireCandidateResolver(); + + @Override public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { return bdHolder.getBeanDefinition().isAutowireCandidate(); @@ -40,6 +47,11 @@ public boolean isRequired(DependencyDescriptor descriptor) { return descriptor.isRequired(); } + @Override + public boolean hasQualifier(DependencyDescriptor descriptor) { + return false; + } + @Override @Nullable public Object getSuggestedValue(DependencyDescriptor descriptor) { @@ -52,4 +64,13 @@ public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, return null; } + /** + * This implementation returns {@code this} as-is. + * @see #INSTANCE + */ + @Override + public AutowireCandidateResolver cloneIfNecessary() { + return this; + } + }