/*
* 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.
* You may obtain a copy of the License at
*
* https://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.beans.factory.support;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
A root bean definition represents the merged bean definition that backs a specific bean in a Spring BeanFactory at runtime. It might have been created from multiple original bean definitions that inherit from each other, typically registered as GenericBeanDefinitions
. A root bean definition is essentially the 'unified' bean definition view at runtime. Root bean definitions may also be used for registering individual bean definitions in the configuration phase. However, since Spring 2.5, the preferred way to register bean definitions programmatically is the GenericBeanDefinition
class. GenericBeanDefinition has the advantage that it allows to dynamically define parent dependencies, not 'hard-coding' the role as a root bean definition.
Author: Rod Johnson, Juergen Hoeller See Also:
/**
* A root bean definition represents the merged bean definition that backs
* a specific bean in a Spring BeanFactory at runtime. It might have been created
* from multiple original bean definitions that inherit from each other,
* typically registered as {@link GenericBeanDefinition GenericBeanDefinitions}.
* A root bean definition is essentially the 'unified' bean definition view at runtime.
*
* <p>Root bean definitions may also be used for registering individual bean definitions
* in the configuration phase. However, since Spring 2.5, the preferred way to register
* bean definitions programmatically is the {@link GenericBeanDefinition} class.
* GenericBeanDefinition has the advantage that it allows to dynamically define
* parent dependencies, not 'hard-coding' the role as a root bean definition.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see GenericBeanDefinition
* @see ChildBeanDefinition
*/
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
@Nullable
private BeanDefinitionHolder decoratedDefinition;
@Nullable
private AnnotatedElement qualifiedElement;
Determines if the definition needs to be re-merged. /** Determines if the definition needs to be re-merged. */
volatile boolean stale;
boolean allowCaching = true;
boolean isFactoryMethodUnique;
@Nullable
volatile ResolvableType targetType;
Package-visible field for caching the determined Class of a given bean definition. /** Package-visible field for caching the determined Class of a given bean definition. */
@Nullable
volatile Class<?> resolvedTargetType;
Package-visible field for caching if the bean is a factory bean. /** Package-visible field for caching if the bean is a factory bean. */
@Nullable
volatile Boolean isFactoryBean;
Package-visible field for caching the return type of a generically typed factory method. /** Package-visible field for caching the return type of a generically typed factory method. */
@Nullable
volatile ResolvableType factoryMethodReturnType;
Package-visible field for caching a unique factory method candidate for introspection. /** Package-visible field for caching a unique factory method candidate for introspection. */
@Nullable
volatile Method factoryMethodToIntrospect;
Common lock for the four constructor fields below. /** Common lock for the four constructor fields below. */
final Object constructorArgumentLock = new Object();
Package-visible field for caching the resolved constructor or factory method. /** Package-visible field for caching the resolved constructor or factory method. */
@Nullable
Executable resolvedConstructorOrFactoryMethod;
Package-visible field that marks the constructor arguments as resolved. /** Package-visible field that marks the constructor arguments as resolved. */
boolean constructorArgumentsResolved = false;
Package-visible field for caching fully resolved constructor arguments. /** Package-visible field for caching fully resolved constructor arguments. */
@Nullable
Object[] resolvedConstructorArguments;
Package-visible field for caching partly prepared constructor arguments. /** Package-visible field for caching partly prepared constructor arguments. */
@Nullable
Object[] preparedConstructorArguments;
Common lock for the two post-processing fields below. /** Common lock for the two post-processing fields below. */
final Object postProcessingLock = new Object();
Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied. /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied. */
boolean postProcessed = false;
Package-visible field that indicates a before-instantiation post-processor having kicked in. /** Package-visible field that indicates a before-instantiation post-processor having kicked in. */
@Nullable
volatile Boolean beforeInstantiationResolved;
@Nullable
private Set<Member> externallyManagedConfigMembers;
@Nullable
private Set<String> externallyManagedInitMethods;
@Nullable
private Set<String> externallyManagedDestroyMethods;
Create a new RootBeanDefinition, to be configured through its bean
properties and configuration methods.
See Also:
/**
* Create a new RootBeanDefinition, to be configured through its bean
* properties and configuration methods.
* @see #setBeanClass
* @see #setScope
* @see #setConstructorArgumentValues
* @see #setPropertyValues
*/
public RootBeanDefinition() {
super();
}
Create a new RootBeanDefinition for a singleton.
Params: - beanClass – the class of the bean to instantiate
See Also:
/**
* Create a new RootBeanDefinition for a singleton.
* @param beanClass the class of the bean to instantiate
* @see #setBeanClass
*/
public RootBeanDefinition(@Nullable Class<?> beanClass) {
super();
setBeanClass(beanClass);
}
Create a new RootBeanDefinition for a singleton bean, constructing each instance
through calling the given supplier (possibly a lambda or method reference).
Params: - beanClass – the class of the bean to instantiate
- instanceSupplier – the supplier to construct a bean instance,
as an alternative to a declaratively specified factory method
See Also: Since: 5.0
/**
* Create a new RootBeanDefinition for a singleton bean, constructing each instance
* through calling the given supplier (possibly a lambda or method reference).
* @param beanClass the class of the bean to instantiate
* @param instanceSupplier the supplier to construct a bean instance,
* as an alternative to a declaratively specified factory method
* @since 5.0
* @see #setInstanceSupplier
*/
public <T> RootBeanDefinition(@Nullable Class<T> beanClass, @Nullable Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setInstanceSupplier(instanceSupplier);
}
Create a new RootBeanDefinition for a scoped bean, constructing each instance
through calling the given supplier (possibly a lambda or method reference).
Params: - beanClass – the class of the bean to instantiate
- scope – the name of the corresponding scope
- instanceSupplier – the supplier to construct a bean instance,
as an alternative to a declaratively specified factory method
See Also: Since: 5.0
/**
* Create a new RootBeanDefinition for a scoped bean, constructing each instance
* through calling the given supplier (possibly a lambda or method reference).
* @param beanClass the class of the bean to instantiate
* @param scope the name of the corresponding scope
* @param instanceSupplier the supplier to construct a bean instance,
* as an alternative to a declaratively specified factory method
* @since 5.0
* @see #setInstanceSupplier
*/
public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {
super();
setBeanClass(beanClass);
setScope(scope);
setInstanceSupplier(instanceSupplier);
}
Create a new RootBeanDefinition for a singleton,
using the given autowire mode.
Params: - beanClass – the class of the bean to instantiate
- autowireMode – by name or type, using the constants in this interface
- dependencyCheck – whether to perform a dependency check for objects
(not applicable to autowiring a constructor, thus ignored there)
/**
* Create a new RootBeanDefinition for a singleton,
* using the given autowire mode.
* @param beanClass the class of the bean to instantiate
* @param autowireMode by name or type, using the constants in this interface
* @param dependencyCheck whether to perform a dependency check for objects
* (not applicable to autowiring a constructor, thus ignored there)
*/
public RootBeanDefinition(@Nullable Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
super();
setBeanClass(beanClass);
setAutowireMode(autowireMode);
if (dependencyCheck && getResolvedAutowireMode() != AUTOWIRE_CONSTRUCTOR) {
setDependencyCheck(DEPENDENCY_CHECK_OBJECTS);
}
}
Create a new RootBeanDefinition for a singleton,
providing constructor arguments and property values.
Params: - beanClass – the class of the bean to instantiate
- cargs – the constructor argument values to apply
- pvs – the property values to apply
/**
* Create a new RootBeanDefinition for a singleton,
* providing constructor arguments and property values.
* @param beanClass the class of the bean to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
*/
public RootBeanDefinition(@Nullable Class<?> beanClass, @Nullable ConstructorArgumentValues cargs,
@Nullable MutablePropertyValues pvs) {
super(cargs, pvs);
setBeanClass(beanClass);
}
Create a new RootBeanDefinition for a singleton,
providing constructor arguments and property values.
Takes a bean class name to avoid eager loading of the bean class.
Params: - beanClassName – the name of the class to instantiate
/**
* Create a new RootBeanDefinition for a singleton,
* providing constructor arguments and property values.
* <p>Takes a bean class name to avoid eager loading of the bean class.
* @param beanClassName the name of the class to instantiate
*/
public RootBeanDefinition(String beanClassName) {
setBeanClassName(beanClassName);
}
Create a new RootBeanDefinition for a singleton,
providing constructor arguments and property values.
Takes a bean class name to avoid eager loading of the bean class.
Params: - beanClassName – the name of the class to instantiate
- cargs – the constructor argument values to apply
- pvs – the property values to apply
/**
* Create a new RootBeanDefinition for a singleton,
* providing constructor arguments and property values.
* <p>Takes a bean class name to avoid eager loading of the bean class.
* @param beanClassName the name of the class to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
*/
public RootBeanDefinition(String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
setBeanClassName(beanClassName);
}
Create a new RootBeanDefinition as deep copy of the given
bean definition.
Params: - original – the original bean definition to copy from
/**
* Create a new RootBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
*/
public RootBeanDefinition(RootBeanDefinition original) {
super(original);
this.decoratedDefinition = original.decoratedDefinition;
this.qualifiedElement = original.qualifiedElement;
this.allowCaching = original.allowCaching;
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
this.targetType = original.targetType;
this.factoryMethodToIntrospect = original.factoryMethodToIntrospect;
}
Create a new RootBeanDefinition as deep copy of the given
bean definition.
Params: - original – the original bean definition to copy from
/**
* Create a new RootBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
*/
RootBeanDefinition(BeanDefinition original) {
super(original);
}
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
Register a target definition that is being decorated by this bean definition.
/**
* Register a target definition that is being decorated by this bean definition.
*/
public void setDecoratedDefinition(@Nullable BeanDefinitionHolder decoratedDefinition) {
this.decoratedDefinition = decoratedDefinition;
}
Return the target definition that is being decorated by this bean definition, if any.
/**
* Return the target definition that is being decorated by this bean definition, if any.
*/
@Nullable
public BeanDefinitionHolder getDecoratedDefinition() {
return this.decoratedDefinition;
}
Specify the AnnotatedElement
defining qualifiers, to be used instead of the target class or factory method. See Also: Since: 4.3.3
/**
* Specify the {@link AnnotatedElement} defining qualifiers,
* to be used instead of the target class or factory method.
* @since 4.3.3
* @see #setTargetType(ResolvableType)
* @see #getResolvedFactoryMethod()
*/
public void setQualifiedElement(@Nullable AnnotatedElement qualifiedElement) {
this.qualifiedElement = qualifiedElement;
}
Return the AnnotatedElement
defining qualifiers, if any. Otherwise, the factory method and target class will be checked. Since: 4.3.3
/**
* Return the {@link AnnotatedElement} defining qualifiers, if any.
* Otherwise, the factory method and target class will be checked.
* @since 4.3.3
*/
@Nullable
public AnnotatedElement getQualifiedElement() {
return this.qualifiedElement;
}
Specify a generics-containing target type of this bean definition, if known in advance.
Since: 4.3.3
/**
* Specify a generics-containing target type of this bean definition, if known in advance.
* @since 4.3.3
*/
public void setTargetType(ResolvableType targetType) {
this.targetType = targetType;
}
Specify the target type of this bean definition, if known in advance.
Since: 3.2.2
/**
* Specify the target type of this bean definition, if known in advance.
* @since 3.2.2
*/
public void setTargetType(@Nullable Class<?> targetType) {
this.targetType = (targetType != null ? ResolvableType.forClass(targetType) : null);
}
Return the target type of this bean definition, if known
(either specified in advance or resolved on first instantiation).
Since: 3.2.2
/**
* Return the target type of this bean definition, if known
* (either specified in advance or resolved on first instantiation).
* @since 3.2.2
*/
@Nullable
public Class<?> getTargetType() {
if (this.resolvedTargetType != null) {
return this.resolvedTargetType;
}
ResolvableType targetType = this.targetType;
return (targetType != null ? targetType.resolve() : null);
}
Return a ResolvableType
for this bean definition, either from runtime-cached type information or from configuration-time setTargetType(ResolvableType)
or AbstractBeanDefinition.setBeanClass(Class<?>)
, also considering resolved factory method definitions. See Also: Since: 5.1
/**
* Return a {@link ResolvableType} for this bean definition,
* either from runtime-cached type information or from configuration-time
* {@link #setTargetType(ResolvableType)} or {@link #setBeanClass(Class)},
* also considering resolved factory method definitions.
* @since 5.1
* @see #setTargetType(ResolvableType)
* @see #setBeanClass(Class)
* @see #setResolvedFactoryMethod(Method)
*/
@Override
public ResolvableType getResolvableType() {
ResolvableType targetType = this.targetType;
if (targetType != null) {
return targetType;
}
ResolvableType returnType = this.factoryMethodReturnType;
if (returnType != null) {
return returnType;
}
Method factoryMethod = this.factoryMethodToIntrospect;
if (factoryMethod != null) {
return ResolvableType.forMethodReturnType(factoryMethod);
}
return super.getResolvableType();
}
Determine preferred constructors to use for default construction, if any.
Constructor arguments will be autowired if necessary.
Returns: one or more preferred constructors, or null
if none (in which case the regular no-arg default constructor will be called) Since: 5.1
/**
* Determine preferred constructors to use for default construction, if any.
* Constructor arguments will be autowired if necessary.
* @return one or more preferred constructors, or {@code null} if none
* (in which case the regular no-arg default constructor will be called)
* @since 5.1
*/
@Nullable
public Constructor<?>[] getPreferredConstructors() {
return null;
}
Specify a factory method name that refers to a non-overloaded method.
/**
* Specify a factory method name that refers to a non-overloaded method.
*/
public void setUniqueFactoryMethodName(String name) {
Assert.hasText(name, "Factory method name must not be empty");
setFactoryMethodName(name);
this.isFactoryMethodUnique = true;
}
Specify a factory method name that refers to an overloaded method.
Since: 5.2
/**
* Specify a factory method name that refers to an overloaded method.
* @since 5.2
*/
public void setNonUniqueFactoryMethodName(String name) {
Assert.hasText(name, "Factory method name must not be empty");
setFactoryMethodName(name);
this.isFactoryMethodUnique = false;
}
Check whether the given candidate qualifies as a factory method.
/**
* Check whether the given candidate qualifies as a factory method.
*/
public boolean isFactoryMethod(Method candidate) {
return candidate.getName().equals(getFactoryMethodName());
}
Set a resolved Java Method for the factory method on this bean definition.
Params: - method – the resolved factory method, or
null
to reset it
Since: 5.2
/**
* Set a resolved Java Method for the factory method on this bean definition.
* @param method the resolved factory method, or {@code null} to reset it
* @since 5.2
*/
public void setResolvedFactoryMethod(@Nullable Method method) {
this.factoryMethodToIntrospect = method;
}
Return the resolved factory method as a Java Method object, if available.
Returns: the factory method, or null
if not found or not resolved yet
/**
* Return the resolved factory method as a Java Method object, if available.
* @return the factory method, or {@code null} if not found or not resolved yet
*/
@Nullable
public Method getResolvedFactoryMethod() {
return this.factoryMethodToIntrospect;
}
public void registerExternallyManagedConfigMember(Member configMember) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedConfigMembers == null) {
this.externallyManagedConfigMembers = new HashSet<>(1);
}
this.externallyManagedConfigMembers.add(configMember);
}
}
public boolean isExternallyManagedConfigMember(Member configMember) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedConfigMembers != null &&
this.externallyManagedConfigMembers.contains(configMember));
}
}
public void registerExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedInitMethods == null) {
this.externallyManagedInitMethods = new HashSet<>(1);
}
this.externallyManagedInitMethods.add(initMethod);
}
}
public boolean isExternallyManagedInitMethod(String initMethod) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedInitMethods != null &&
this.externallyManagedInitMethods.contains(initMethod));
}
}
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
synchronized (this.postProcessingLock) {
if (this.externallyManagedDestroyMethods == null) {
this.externallyManagedDestroyMethods = new HashSet<>(1);
}
this.externallyManagedDestroyMethods.add(destroyMethod);
}
}
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
synchronized (this.postProcessingLock) {
return (this.externallyManagedDestroyMethods != null &&
this.externallyManagedDestroyMethods.contains(destroyMethod));
}
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof RootBeanDefinition && super.equals(other)));
}
@Override
public String toString() {
return "Root bean: " + super.toString();
}
}