编程知识 cdmana.com

Spring source code learning 5 - circular dependency

One 、 The reasons causing

As I said before Spring bean Life cycle of , We know bean After instantiation , Properties to be populated 、 After the initialization is complete, it can be put into the singleton pool for use . that , If beanA rely on beanB,beanA When the attribute is filled, it will trigger beanB Life cycle of . and beanB Depend on beanA You will find beanA Not ready to inject , Will fall into a dead cycle of waiting for each other , This is circular dependency . Pictured
 Insert picture description here

Two 、 Three level cache

Spring In order to solve the circular dependence , Three level cache is used , The third level cache corresponds to DefaultSingletonBeanRegistry Class defines three Map. Be careful , Their order is not defined by one, two, three
 Insert picture description here

2.1 Environmental preparation

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring {
    
    public static void main(String[] args) {
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Object o = context.getBean("userService");
        System.out.println(o);
    }
}

AppConfig

import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.spring.study.service")
public class AppConfig {
    
}

OrderService

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class OrderService {
    

    @Autowired
    private UserService userService;
}

UserService

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UserService {
    
    @Autowired
    private OrderService orderService;
}

2.2 Source tracking

I understand bean Life cycle of , We from getBean(“orderService”)——>doGetBean——>getSingleton Get into
 Insert picture description here

2.2.1 OrderService Acquisition process

OrderService Let's start with
 Insert picture description here
This has started to use L3 cache , First level cache singletonObjects Not yet OrderService Example ,OrderService I haven't started creating , So I won't enter... For the first time if, Then go on
 Insert picture description here
This one is in bean The life cycle of , I won't repeat . stay getSingleton It will execute this lamba, Get into createBean——>doCreateBean
 Insert picture description here
before this bean Instantiated , If bean Is a singleton , Allow circular dependency , And is creating and entering if. This is the most critical place ,addSingletonFactory Used to break the cycle
 Insert picture description here

Single example bean Put your factory into L3 cache singletonFactories, In order to execute getObject() Get instantiated bean.
Go back and see getEarlyBeanReference
 Insert picture description here
If bean, Have quilt AOP, What's back here is AOP After that, the proxy object , Otherwise, it is the original object ,AOP Later on .
 Insert picture description here
current bean Has been instantiated , Not initialized .populateBean Fill properties , Will trigger UserService Life cycle of getBean(“userService”)
 Insert picture description here

2.2.2 UserService Acquisition process

UserService With the process of OrderService similar , Once again into the populateBean Method , Fill properties , At this time, we need to inject a orderService. Get into populateBean–>ibp.postProcessProperties, Enter into AutowiredAnnotationBeanPostProcessor Handle automatic assembly
 Insert picture description here
Continue to enter , This piece of processing orderService Field  Insert picture description here
Continue to enter resolveDependency–>doResolveDependency–>descriptor.resolveCandidate(autowiredBeanName, type, this);
 Insert picture description here

Back again getBean(“orderService”)

2.2.3 Again OrderService Acquisition process

Once again into the getSingleton,orderService It's being created , So we entered if, At this point 、 The L2 cache is empty , Only the L3 cache has bean Our factory  Insert picture description here
call getObject(), Got it. orderService Examples of early exposure , Then promote the instance to the L2 cache , Delete the value of L3 cache . All the way back , It's done orderService The injection of , Finish again UserService The initialization of is put into the first level cache . Continue to complete userService Injection into OrderService, complete OrderService The initialization .
 Insert picture description here
Then here will be OrderService The instance is promoted to the first level cache
 Insert picture description here
Delete the cache in Level 2 and level 3 again . up to now OrderService and UserService All instances are added to the first level cache , Solved the circular dependency between them . In this process, L2 cache earlySingletonObjects, It doesn't seem to work ,userService Join first earlySingletonObjects, Then add the L1 cache singletonObjects At the same time earlySingletonObjects Delete in . It feels like a bit of an unnecessary move , Let's see why we need L3 cache

3、 ... and 、 Why do I need L3 cache , Is two levels OK

singletonObjects First level cache
earlySingletonObjects Second level cache
singletonFactory Three level cache

3.1 Process carding

BeanA Instantiation –> Put it in the third level cache –> Fill properties BeanB,BeanC–>

( Trigger BeanB Instantiation –> Put it in the third level cache –> Fill properties BeanA–>BeanA It's being created , Fetch from L3 cache –> obtain AOP After that BeanA, Put it in the second level cache –> Conduct BeanB Of AOP–> complete beanB establish –>BeanB Put it in the first level cache )–>
( Trigger BeanC Instantiation –> Put it in the third level cache –> Fill properties BeanA–>BeanA Fetch from L2 cache –> obtain AOP After that BeanA–> Conduct BeanB Of AOP–> complete beanB establish –>BeanC Put it in the first level cache )–>

To determine whether or not AOP–> Already ahead of schedule AOP–> complete benaA The creation of –>BeanA Put it in the first level cache

3.2 analysis

  • BeanB、BeanC Of AOP After filling in the attributes
  • BeanA Of AOP In L3 cache , That is, before filling the attributes , advance AOP 了
  • If there is no L2 cache ,BeanC In the process of creation, it is obtained from the L3 cache again BeanA Will be a new AOP object , Because every time AOP After that, the proxy objects are different , Is not workable
  • If there is no L3 cache , After instantiation BeanA Put it directly into the L2 cache , Inject BeanB,BeanC An example of this is without AOP Of . and BeanA Final meeting AOP Then put it into the L1 cache , Is not workable
  • If there is no L3 cache , After instantiation BeanA Go first AOP Then put it into the L2 cache , That's ok . however , After doing so, all bean Of AOP It's all ahead of time . actual Spring It is hoped that only circular dependencies occur bean Just in advance AOP
  • therefore , After instantiation BeanA, Create a for AOP Our factory , Put this factory into L3 cache . When circular dependency occurs, it is taken out from the factory and passed through AOP Of BeanA, Then pass through AOP Of BeanA Put it in the second level cache . such BeanA Medium BeanB、BeanC Can get the same from the L2 cache AOP After that BeanA, Only BeanA Of AOP Ahead of schedule. .

3.3 Conclusion

  1. The L3 cache ensures that only circular dependencies occur bean advance AOP
  2. The L2 cache ensures that multiple attribute circular dependencies can get the same AOP After that Bean
  3. The L1 cache is the final singleton pool ,bean After putting it in , Delete two 、 Third level cache bean.
  4. Two 、 The third level cache exists to solve the circular dependency , If there is no circular dependency , First level cache is enough .
  5. There are circular dependencies , No, AOP, Two level cache is enough .

版权声明
本文为[Integer_ Double]所创,转载请带上原文链接,感谢
https://cdmana.com/2022/134/202205141343410686.html

Scroll to Top