/*
 * 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(); } }