This is the first day of my participation in Gwen Challenge

The previous article focused on what the Spring source factory post-processor does, namely the Spring project scans, parses, and gets beanDefinition and all beanName, as well as the @import annotation. , and the application of introducing ImportSelector and ImportBeanDefinitionRegistrar, interested can look at the front.

This article began to write bean instantiation process, read the source code is more boring, related articles are also more boring, I try to write simple and clear point.

1. An overview of the

The above figure Outlines the entire bean creation process. Spring first fetches the bean from the cache pool before creating the bean, and then creates the bean when it is not available from the cache pool. For those of you familiar with spring’s source code, there are three levels of caching:

  • Level 1 cache: singletonObjects –> pool of singletonObjects that hold complete beans
  • Level 2 cache: earlySingletonObjects — a singleton pool of incomplete beans, containing beans that were exposed earlier
  • SingletonFactories –> stores the factories that can be used to create beans

During bean creation, bean post-processing is used to get the bean constructor, create the bean, and then wrap the bean proxy. If the bean does not need to wrap the proxy, an early exposed object is returned and placed in the secondary cache. If the bean needs to wrap the proxy, It returns a factory and puts it in a level 3 cache.

The bean is then assembled. This process is to assemble the bean’s properties. When the bean is assembled, the bean is considered a complete bean, and the complete bean is finally put into the singleton pool, which is the level 1 cache.

This is the whole process of bean creation, here is an overview, but also want to read this article in the heart of the students have a general, after not dizzy, let’s enter the source code reading stage.

2. GetBean from the cache pool

AbstractBeanFactory#doGetBean(), which starts by fetching beans from a singleton pool:

Now click on this method to see how to get the bean from the cache:

If the bean is not available and the current bean is being created, the bean is fetched from the level 2 cache. If the level 2 cache is not available, the factory object is fetched from the level 3 cache. If the factory object is available, the bean is fetched from the factory. Finally, the bean is placed in a level 2 cache.

Since the Spring project will definitely not have a bean object in the cache when it starts, you need to create the bean, and see how the bean is created.

3. Create a bean

Again with the doGetBean() method, take a look at the most important snippet:

There are two methods: createBean(beanName, MBD, args); Click on this method to see if it omits some unimportant code:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   / /... .

   // Prepare method overrides.
   try {
      /** * handles lookup-Method and replace-method, collectively known as overrides */
      mbdToUse.prepareMethodOverrides();
   }
   / /... .

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      There is a post processor inside the / * * *, if the post processor can return a bean, is returned directly, no longer on the back of the assembly, * InstantiationAwareBeanPostProcessor * / ignore it
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if(bean ! =null) {
         returnbean; }}/ /... .

   try {
      /** * Create object */
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
  / /... .
}
Copy the code

Can see the code snippet, the first is to deal with overrides, then go to call a rear bean processing (InstantiationAwareBeanPostProcessor) method, if the method returns an object, it returns the object, not on the back of the bean creation process.

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

The first part of this method is to create the bean object:

To see how to create a wrapper object, click on this method: instanceWrapper = createBeanInstance(beanName, MBD, args); Still omit some unimportant code:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   / /... .
   /** * instantiates the object */ as supplierSupplier<? > instanceSupplier = mbd.getInstanceSupplier();if(instanceSupplier ! =null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   / * * * if FactoryMethodName is empty, not through instantiateUsingFactoryMethod () * to instantiate the object through XML to specify FactoryMethodName *@BeanWhen static, you're assigning a FactoryMethodName * to your object. When it's not static, Is uniqueFactoryMethodName * specific see ConfigurationClassPostProcessor * /
   if(mbd.getFactoryMethodName() ! =null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   /** * From the original comments of Spring, we know that this is a Shortcut. What does it mean? * When building the same bean multiple times, you can use Shortcut * that is, you don't need to infer again which way to construct the bean */
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if(mbd.resolvedConstructorOrFactoryMethod ! =null) {
            resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; }}}if (resolved) {
      if (autowireNecessary) {
         return autowireConstructor(beanName, mbd, null.null);
      }
      else {
         returninstantiateBean(beanName, mbd); }}// Candidate constructors for autowiring?
   / * * * by the post processor (SmartInstantiationAwareBeanPostProcessor) decided to return to a parameter of the constructor * if there is only one constructor, this returns null * /Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);/** * automatic assembly model! = Autowiring technology * Autowiring model defaults to 0 */
   if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   ctors = mbd.getPreferredConstructors();
   if(ctors ! =null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   /** * is initialized with the default no-argument constructor */
   return instantiateBean(beanName, mbd);
}
Copy the code

The bean is instantiated using the supplier method, instantiated using the FactoryMethodName method, and then found using the bean’s post-processor to find the bean’s constructor. If defined in the bean has a constructor, it returns a constructor, determineConstructorsFromBeanPostProcessors (beanClass, beanName); There is some logic in this, and you can look at it for yourself. If you don’t find a constructor with arguments, return the default constructor with no arguments. This returns a BeanWrapper object.

4. Proxy bean, put into level 3 cache

The bean has already been instantiated, because some objects in Spring need to be proxied. Look at this code:

In getEarlyBeanReference (beanName, MBD, beans)); In this method, we actually execute the method in the bean post-processor to proxy the bean:

Object proxy = createProxy(
      bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
Copy the code

Finally, the ProxyFactory#getProxy method is called:

This is the JDK proxy and Cglib proxy

Then look at the addSingletonFactory() method:

protected void addSingletonFactory(String beanName, ObjectFactory
        singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName); }}}Copy the code

This is where we put the Factory object into the level 3 cache.

5. Assemble beans and loop dependencies

I’m not going to post the code here, but if you’re interested, you can come down and study it. This is populating the bean’s properties, for example, A depends on B, and this is populating B.

Here is a classic problem, is the spring cycle dependency problem, spring exactly how to solve the problem of cycle dependency?

After reading the Spring source code, I drew a picture to show it clearly:

Assuming that A and B depend on each other, when creating A comes to assemble this step, need to go to the assembly B, this time will go to getB, but couldn’t get, will be to create A B, when creating A B to assemble this step, the need to assemble A, and A the bean has been created, and in the cache, you can get A, B will be finished assembly at this time, And when B is assembled, corresponding A is assembled.

Finally, both A and B are A complete bean, which is then put into the level 1 cache, the singleton pool.

The whole process of bean creation and spring’s cyclic dependencies are covered here. Hopefully, those who read this article will learn something from it.