preface

This is all preparation, but the next step is to initialize the BeanFactory and instantiate the singleton Bean.

Specific how to operate, then read the source code together!

But before reading the source code, there are some things you need to know.

  1. What is a FactoryBean?
  2. How is a FactoryBean used?
  3. How is the Bean initialized?
  4. What is the solution to cyclic dependency?

What is a FactoryBean?

In the article “What’s a FactoryBean? There are relevant answers, interested partners can take a look.

Interfaces implemented by internally used objects, beanFactories themselves being factories for individual objects. If the bean implements this interface, it will be used as a factory to expose the object, rather than directly as the bean instance to expose itself.

Note: The bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in bean-style, but the object exposed for the bean reference (getObject()) is always the object it created.

FactoryBeans can support singletons and prototypes, and objects can be created either on demand or in a hurry at startup.

When a FactoryBean is born, there are two types of Bean: the FactoryBean itself and the Bean of the type it needs to create.

Here is an example:

use

1. PaidComponent

public class PaidComponent {

	public PaidComponent(a) {
		System.out.println("PaidComponent no-argument construct called"); }}Copy the code

2. PaidComponentFactoryBean

@Component
public class PaidComponentFactoryBean implements FactoryBean<PaidComponent> {

	@Override
	public PaidComponent getObject(a) throws Exception {

		System.out.println("GetObject method called for PaidComponentFactoryBean");

		return new PaidComponent();
	}

	@Override
	publicClass<? > getObjectType() {returnPaidComponent.class; }}Copy the code

3 Test

public class AnnotationConfigApplicationTest {

	public static void main(String[] args) {

		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

		context.register(JavaConfig.class);


		context.refresh();


		System.out.println(context.getBean("paidComponentFactoryBean"));
		System.out.println(context.getBean("&paidComponentFactoryBean")); System.out.println(context.getBean(PaidComponent.class)); }}Copy the code

PaidComponentFactoryBean paidComponentFactoryBean paidComponentFactoryBean

Getting paidComponentFactoryBean directly gets the type returned by FactoryBean’s getObject() method.

FinishBeanFactoryInitialization source

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    // Initialize the type converter
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    // Mainly used for annotation attribute value parsing
    if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    // Initialize the LoadTimeWeaverAware Bean as early as possible to register its converter as early as possible.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    // Stop using temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    // Set the beanDefinition metadata to be unmodifiable
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    // Instantiate the singleton bean
    beanFactory.preInstantiateSingletons();
}
Copy the code

Focus on the last line here

beanFactory.preInstantiateSingletons();

preInstantiateSingletons

This is entering class DefaultListableBeanFactory class source code.

public void preInstantiateSingletons(a) throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    // Place beanDefinitionNames in the collection
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    / / traverse
    for (String beanName : beanNames) {
        // Get bd information, as parentBeanDefinition may be defined
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // Non-abstract, singleton, and not lazy loading
        if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {// Determine if it is a FactoryBean
            if (isFactoryBean(beanName)) {
                // FactoryBean needs to be prefixed with &. GetBean (&beanName) gets the FactoryBean itself
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceofFactoryBean) { FactoryBean<? > factory = (FactoryBean<? >) bean;// Determine whether initialization is required
                    boolean isEagerInit;
                    if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
                        isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }// Initialization is required
                    if(isEagerInit) { getBean(beanName); }}}else{ getBean(beanName); }}}// Trigger post-initialization callback for all applicable beans...
    / / if the Bean implementation SmartInitializingSingleton,
    / / here will be unified call afterSingletonsInstantiated method
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
                    .tag("beanName", beanName);
            SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if(System.getSecurityManager() ! =null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else{ smartSingleton.afterSingletonsInstantiated(); } smartInitialize.end(); }}}Copy the code

In the above method, the Bean is initialized by looping beanNames.

You need to distinguish BeanFactory from regular beans. That’s why I first introduced what is a BeanFactory?

Now you need to focus on the getBean(beanName) method.

getBean

public Object getBean(String name) throws BeansException {
    return doGetBean(name, null.null.false);
}
Copy the code

The doGetBean method is called in the getBean method.

doGetBean

The doGetBean method returns an instance, which can be shared or independent of the specified bean.

The method accepts four parameters:

Name – the name of the bean to retrieve requiredType – the requiredType of the bean to retrieve, This can be empty args – the parameter to use when creating bean instances with explicit arguments (only applied when creating new instances rather than retrieving existing ones) typeCheckOnly – whether to get instances for type checking rather than actual use

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {

    // Remove the prefix referenced by the factory and transform the alias
    String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    // Check whether the singleton already exists from the cache
    Object sharedInstance = getSingleton(beanName);
    if(sharedInstance ! =null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); }}If obtained from the cache, the normal Bean returns directly, and the FactoryBean returns the Bean created by the FactoryBean
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // Returns whether the specified prototype bean (of type prototype) is currently being created (in the current thread).
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        // Check whether the BeanFactory has a BeanDefinition for this Bean
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            // Check for definitions in the parent container
            String nameToLookup = originalBeanName(name);
            // Returns the result of the query from the parent container
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if(args ! =null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if(requiredType ! =null) {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return(T) parentBeanFactory.getBean(nameToLookup); }}if(! typeCheckOnly) {// Put the current beanName into an alreadyCreated Set.
            // This method is not called to get the type of the bean, but to create an instance of the beanName into the alreadyCreated collection, indicating that the bean has been created. Catch clears the beanName if an exception occurs
            markBeanAsCreated(beanName);
        }

        StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
                .tag("beanName", name);
        try {
            if(requiredType ! =null) {
                beanCreation.tag("beanType", requiredType::toString);
            }
            // Get the BeanDefinition of the Bean
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            // Make sure the dependent Bean is already initialized, such as @dependson annotation
            String[] dependsOn = mbd.getDependsOn();
            if(dependsOn ! =null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        // Create the dependent Bean
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}// Create bean instance.
            if (mbd.isSingleton()) {
                / / the singleton beans
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // Explicitly remove instance from singleton cache: It might have been put there
                        // eagerly by the creation process, to allow for circular reference resolution.
                        // Also remove any beans that received a temporary reference to the bean.
                        destroySingleton(beanName);
                        throwex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }// Create the prototype Bean
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                // Delegate to the implementation class
                String scopeName = mbd.getScope();
                if(! StringUtils.hasLength(scopeName)) {throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
                }
                Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally{ afterPrototypeCreation(beanName); }}); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); }catch (IllegalStateException ex) {
                    throw newScopeNotActiveException(beanName, scopeName, ex); }}}catch (BeansException ex) {
            beanCreation.tag("exception", ex.getClass().toString());
            beanCreation.tag("message", String.valueOf(ex.getMessage()));
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
        finally{ beanCreation.end(); }}// Check if required type matches the type of the actual bean instance.
    // Check that the desired type matches the type of the actual bean instance.
    if(requiredType ! =null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}return (T) bean;
}
Copy the code

The above code is quite long, and corresponding annotations have been added for the basic steps, which can be basically divided into three steps:

  1. Get the Bean from the cache and create the corresponding Bean;
  2. If no Bean is retrieved from the cache, create the corresponding Bean.
  3. Check that the desired type matches the type of the actual bean instance.

Here are the three steps:

  • Get the Bean from the cache and create the corresponding Bean

Object sharedInstance = getSingleton(beanName);

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}
/** * returns the (original) singleton registered with the given name. * * Checks for instantiated singletons and allows early references to currently created singletons (parse circular references) */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock
    // private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    // The singleton Bean is cached
    Object singletonObject = this.singletonObjects.get(beanName);
    // If not, and the current Bean is being created
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
        // The early singleton is first fetched from earlySingletonObjects
        singletonObject = this.earlySingletonObjects.get(beanName);
        // Not retrieved from earlySingletonObjects cache
        if (singletonObject == null && allowEarlyReference) {
            synchronized (this.singletonObjects) {
                // Consistent creation of early reference within full singleton lock
                // Get and check again
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        // private final Map
      
       > singletonFactories = new HashMap<>(16);
      ,>
                        // from the singletonFactories cacheObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
                        if(singletonFactory ! =null) {
                            singletonObject = singletonFactory.getObject();
                            // Add to earlySingletonObjects cache
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            // Delete from the singletonFactories cache
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}
Copy the code

Here we can see that getting a Bean:

  1. From the firstsingletonObjectsGet Bean from;
  2. Failed to obtain fromearlySingletonObjectsGet Bean from;
  3. Failed to obtain fromsingletonFactoriesGets the Bean from.

Of course, this section deals with circular references, and space is limited, so we’ll cover circular references later.

  • If no Bean is retrieved from the cache, create the corresponding Bean
// Create bean instance.
if (mbd.isSingleton()) {
    / / the singleton beans
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throwex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }else if (mbd.isPrototype()) {
    // Create the prototype Bean
    
} else {
    // Delegate to the implementation class
    String scopeName = mbd.getScope();
}
Copy the code
  • Check that the desired type matches the type of the actual bean instance

conclusion

Here we mainly introduce the Bean creation process, mainly to have a general understanding and familiarity with the whole process, the process is drawn as follows:

The instantiation of beans focuses on the instantiation of singleton beans, which will be discussed in more detail later.

Related to recommend

  • The Spring source study 14: initApplicationEventMulticaster
  • Spring source learning 13: initMessageSource
  • The Spring source learning 12: registerBeanPostProcessors