Exploration of Spring Bean life cycle and how to solve circular dependency

overview

This article is a summary of notes after watching the video of Mr. Zilu. Mr. Zilu has a lot of knowledge in Spring source code. Here are two of his videos for you to recommend: spring
source code-bean life cycle
spring source code-spring circular dependency

1. Spring beans and objects?

  • Spring bean—an object managed by the spring container may have gone through a complete spring bean life cycle, and finally exists in the spring container. The bean is an object instantiated, assembled and managed by the Spring IoC container;A bean must be an object
  • Object - any object that conforms to the java syntax rules instantiated,But an object is not necessarily a spring bean

2. Project structure construction

Next, use IDEA to create a new maven project, import Spring-related jar packages, and use a Demo to demonstrate the Spring bean life cycle process: note that the annotations are used to create objects

@Component
public class Teacher {
    
    
    public Teacher() {
    
    
        System.out.println("Teacher constructor....");
    }
}
@Component
public class User {
    
    
    public User() {
    
    
        System.out.println("User constructor....");
    }
}
@ComponentScan("com.lhg.demo.*")
public class App{
    
    
    public static void main( String[] args ){
    
    
        ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
        ac.getBean("user")
   }
}
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.5.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
  </dependency>
</dependencies>

3. Source code analysis of the process of creating beans in Spring

 ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
 ac.getBean("user")

Enter the constructor of the AnnotationConfigApplicationContext class

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    
    
    public AnnotationConfigApplicationContext() {
    
    
        //由于这个类继承自GenericApplicationContext,
        //按照 java 语法,无参构造方法的首行默认调用父类的无参构造方法
        //初始化一个读取器和扫描器
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    } 
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    
    
        this();//this 表示调用当前类的无参构造方法
        this.register(annotatedClasses);
        this.refresh();
    }
}

If it is configured in xml

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) ac.getBean("user");

Looking at the source code, you will find that the refresh method is also called

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    
    
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    
    
		this(new String[] {
    
    configLocation}, true, null);
	}
	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
    
    
	    super(parent);
	    this.setConfigLocations(configLocations);
	    if (refresh) {
    
    
	        this.refresh();
	    }
	}
}
3.1 this calls the parent class constructor

this means calling the no-argument construction method of the current class (AnnotationConfigApplicationContext). If the class has an inheritance relationship, according to java syntax, the first line of the no-argument construction method defaults to calling the no-argument construction method of the parent class, that is, calling the GenericApplicationContext parent class construction method

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    
    
    //beanFactory 就是 bean 工厂,而在 DefaultListableBeanFactory 类中有个叫 beanDefinitionMap 的 map 容器
    private final DefaultListableBeanFactory beanFactory;
    public GenericApplicationContext() {
    
    
        this.customClassLoader = false;
        this.refreshed = new AtomicBoolean();
        //可以看到在这里初始化了 beanFactory
        this.beanFactory = new DefaultListableBeanFactory();
    }
}
3.2 the this.register(annotatedClasses) method

If we use Spring annotations, such as Component annotations, Spring will scan by itself. The purpose of this method is actually just one sentence this.beanDefinitionMap.put(beanName, beanDefinition). Click into the source code and find that the following method is finally called

public class AnnotatedBeanDefinitionReader {
    
    
	<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    
    
        	//.....这里省略的代码就是把一个类变成 BeanDefinite 的过程
         
        	//BeanDefinitionHolder 其实就包含了 BeanDefinite,到此为止,JavaConfig 就变成了一个BeanDefinition
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }
}

As can be seen from the debug diagram, the App class has not yet become a BeanDefinition object (I will abbreviate it as bd later), and has not been put into the beanDefinateMap
insert image description here

Why should the class be encapsulated into bd instead of a direct class object?

Because bd can contain richer class information, such as whether it is an abstract class, whether it is a singleton/prototype, whether it is lazy loaded...

ok, continue to enter BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);the method, you can see the definition of beanDefinitionMap in the DefaultListableBeanFactory class

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    
	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

  	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    
    
		//省略代码。。。
		//beanName 就是 App,显然 existingDefinition 为 null
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
    
    
		    ...
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
    
    
			if (hasBeanCreationStarted()) {
    
    
				....
			}
			else {
    
    
				// Still in startup registration phase
				//在这里把封装后的 beanDefinition 放入 map 中了
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		...
	}
}

After debugging also confirmed our inference
insert image description here

3.3 analysis of this.refresh() method

So far, we found that User objects and Teacher objects have not been scanned and put into beanDefinitionMap,

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    
    
	public void refresh() throws BeansException, IllegalStateException {
    
    
        synchronized(this.startupShutdownMonitor) {
    
    
            //准备工作包括设置启动时间,是否激活标志位
            //初始化属性源(propertry source)配置
            this.prepareRefresh();
            //返回一个 facotory 工厂,为什么需要返回一个工厂?
            //因为要对工厂进行初始化
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备工厂
            this.prepareBeanFactory(beanFactory);

            try {
    
    
                //这个方法里是没有任何代码的,可能是为了以后的 Spring 扩展吧...
                this.postProcessBeanFactory(beanFactory);
                //在 Spring 环境中去执行已经被注册的 factory processors,
                //设置执行自定义的 ProcessBeanFactory 和 Spring 内部定义的的
                //在进入 refresh 方法之前,已经进行了 scan----- put map----invokeBeanFactoryPostProcessors{1.custom 2.内置的}
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                //实例化对象
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
    
    
                ....
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            }...
        }
    }
}

After breakpoint debugging, it is found that after the method is executed, this.invokeBeanFactoryPostProcessors(beanFactory);the user and teacher classes become bd and put into beanDefinateMap

insert image description here
As I said in the previous code comment, this.invokeBeanFactoryPostProcessors(beanFactory);it will check whether the user has a custom implementation of BeanFactoryPostProcessors during execution. If so, it will also execute user-defined BeanFactoryPostProcessors, which can realize the extension of spring

@Component
public class CustomerBeanFactoryProcessor implements BeanFactoryPostProcessor {
    
    
    /**
     * 你可以看到形参是 DefaultListableBeanFactory 的父类 configurableListableBeanFactory
     * 这是因为如果要兼容 ClassPathXmlApplicationContext("application.xml")的初始化情况
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    
    

        /**
         * 我们用 BeanDefinition 的子类,因为子类实现了更丰富的方法
         * BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("student");
         * **/
        //这里我们通过 BeanFactory 先拿到的是 beanDefinite
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("user");
        //获取到 beanDefinite 后,便可以通过beanDefinite得到 bean 了
        System.out.println("原来的bean:"+beanDefinition.getBeanClassName());
        //当然你可以偷梁换柱,替换成其它的类
        beanDefinition.setBeanClass(Teacher.class);
        System.out.println("后来的bean:"+beanDefinition.getBeanClassName());
    }
}
ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
//本意是输出 user 对象
System.out.println(ac.getBean("user"));

The result after running: the teacher object is finally obtained

D:\ProgramFiles\Java\jdk1.8.0_201\bin\java.exe "-javaagent:
原来的bean:com.lhg.demo.config.User
后来的bean:com.lhg.demo.config.Teacher
Teacher constructor....
Teacher constructor....
com.lhg.demo.config.Teacher@2a70a3d8

Process finished with exit code 0

So what exactly is BeanFactoryPostProcessor?

The so-called BeanFactoryPostProcessor is able to interfere with the initialization process of Spring Bean. As can be seen from our custom CustomerBeanFactoryProcessor class above, we clearly want user objects. After internal processing by the custom BeanFactoryPostProcessor, the output becomes another Teacher object...

finishBeanFactoryInitialization(beanFactory);

After executing the invokeBeanFactoryPostProcessors() method, although the user and teacher have become bd and put into the beanDefinateMap, but checking the console, it is found that their construction methods are still not executed, and the construction method is executed after the method is executed finishBeanFactoryInitialization(beanFactory);. It is in the finishBeanFactoryInitialization method that the object is finally instantiated , so we need to look at finishBeanFactoryInitialization(beanFactory);the method implementation.

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    
	@Override
	public void preInstantiateSingletons() throws BeansException {
    
    
		//...
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		//遍历 map
		for (String beanName : beanNames) {
    
    
			//通过 beanName 获得 bd 对象
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//各种验证
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    
    
				if (isFactoryBean(beanName)) {
    
    //为 false,不是个 factorybean
					//....
				}
				else {
    
    
					getBean(beanName);
				}
			}
		}
	}
}

Then check getBean(beanName);the implementation of the underlying method and notice that the following method getSingleton is two overloaded methods. Through debugging, it is found that the bean is created after the second call to the getSingleton method. In other words, how the entire bean is initialized is in this method. Inside; so far the core code of the doGetBean method exemplified in this article seems to have been parsed;

The following is a simplified doGetBean method;

Again, it is also important to call the getSingleton method for the first time, which contains logic to resolve circular dependencies

Next, we will study the content of the second getSingleton method, because I said that the entire bean initialization process is reflected in it.

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

	final String beanName = transformedBeanName(name);
	Object bean;
	// Eagerly check singleton cache for manually registered singletons.
	//第一次调用getSingleton: 因为是第一次初始化,这里 sharedInstance 显然是为 null,
	//里面的逻辑是实现循环依赖最主要的代码,后文详说
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
    
    
		....
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
    
    
		...
		try {
    
    
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			...
			// Create bean instance.
			if (mbd.isSingleton()) {
    
    
				//第二次调用getSingleton,完成了bean的初始化
				sharedInstance = getSingleton(beanName, () -> {
    
    
					try {
    
    
						return createBean(beanName, mbd, args);
					}
					...
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			else if (mbd.isPrototype()) {
    
    
				// It's a prototype -> create a new instance.
				...
			}
		}
		...
	}
	...
	return (T) bean;
}

The second call to getSingleton uses a lambda expression, the first is to execute the getSingleton(beanName, singletonFactory) method, which is interesting, the key point

	/**
	 * Return the (raw) singleton object registered under the given name,
	 * creating and registering a new one if none registered yet.
	 * @param beanName the name of the bean
	 * @param singletonFactory the ObjectFactory to lazily create the singleton
	 * with, if necessary
	 * @return the registered singleton object
	 */
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
    
    
			Object singletonObject = this.singletonObjects.get(beanName);
			//在spring 初始化bean的时候这里肯定为空,故而成立
			if (singletonObject == null) {
    
    
				if (this.singletonsCurrentlyInDestruction) {
    
    
					throw new BeanCreationNotAllowedException(beanName,
							"...");
				}
				...
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
    
    
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
    
    
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				...
				if (newSingleton) {
    
    
					//这个方法里面 把 bean 放入了单例池,singletonObjects,完成了生命周期
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

The second time getSingleton came up, it was called this.singletonObjects.get(beanName), and the object was obtained directly from the singleton pool. Since it is created here, it must return null; singletonObjects is a map collection, the so-called singleton pool; in plain EnglishAll singleton beans in spring are instantiated and stored in this map, many readers, including me, thought that this is the so-called spring container, but in fact this understanding is wrong, because the concept of the spring container is relatively abstract, and the singleton pool is just a component of the spring container; we often say that the Spring container In fact, it refers to the combination of beanDefinitionMap, BeanFactoryPostProcessors, singletonObjects, etc.

You can look at the definition of singletonObjects

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

This line of code is actually relatively simple, to determine whether the currently instantiated bean is in the destroyed collection; whether the process of destroying or creating a bean in spring is cumbersome, it will first put them in a collection to indicate that it is being created or destroyed;

if (this.singletonsCurrentlyInDestruction) {
    
    
	throw new BeanCreationNotAllowedException(beanName, "...");
}

The following code is more important. Regarding the collection that is being created and destroyed, let’s take a look at the beforeSingletonCreation method, which is very important.

  • this.inCreationCheckExclusions.contains(beanName) here is to judge whether the bean that needs to be created currently is in the Exclusions collection, the excluded bean, the programmer can provide some beans that are not initialized by spring (even if they are scanned, they are not initialized), then these provide The bean will exist in this collection; under normal circumstances, we will not provide it, and it has nothing to do with circular dependencies; therefore, we will not do in-depth analysis here, and if we write it in the following articles, we will do it;

  • this.singletonsCurrentlyInCreation.add(beanName), if the current bean is not in the excluded set, then this bean is added to singletonsCurrentlyInCreation (of course, just add the bean name to the set, because he can find the corresponding bean according to the name)

/**
 * Callback before singleton creation.
 * <p>The default implementation register the singleton as currently in creation.
 * @param beanName the name of the singleton about to be created
 * @see #isSingletonCurrentlyInCreation
 */
protected void beforeSingletonCreation(String beanName) {
    
    
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
    
    
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

When the code is executed to the context here, it can be seen from the above code that when spring thinks it can start to create a bean, it first calls beforeSingletonCreation(beanName); to determine whether the bean currently being instantiated exists in the collection being created, To put it bluntly, it is to judge whether it is currently being created; because spring no matter whether it creates a prototype bean or a singleton bean, when he needs to formally create a bean, he will record that the bean is being created (add to a set collection); so when he officially Before creating it, he has to check whether the bean is being created (whether it exists in the collection);
insert image description here

Why does spring have to judge whether this collection exists?

There are many reasons besides what you can think of (what you can think of will basically not appear, such as concurrency, repeated creation, etc., because it has already done strict concurrency processing),In fact, this collection is mainly for circular dependency services, I will talk about how to solve circular dependencies later

Note: After the code is executed this.singletonsCurrentlyInCreation.add(beanName), you can see that there are already objects in the singletonsCurrentlyInCreation collection, but the console does not print the construction method, indicating that spring only adds the user to the collection being created, but does not complete the bean creation;insert image description here

The next step is to execute createBean, get the class, infer the constructor, and reflect, instantiate the object, and return the created bean

/**
	 * Central method of this class: creates a bean instance,
	 * populates the bean instance, applies post-proce ssors, etc.
	 * @see #doCreateBean
	 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
    
    
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	//得到 class
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
    
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
    
    
		mbdToUse.prepareMethodOverrides();
	}
	try {
    
    
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
    
    
			return bean;
		}
	}
	...
	try {
    
    
		//在 doCreateBean 方法中创建对象
		//推断构造方法,并反射,实例化对象
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
    
    
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {
    
    

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
    
    
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
    
    
		//在这个方法里面完成了对象的创建
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	// Allow post-processors to modify the merged bean definition.
	//从 java-doc 可以看出这里说的是可以通过 post-processors 去 modify 合并的 beandefinition.
	synchronized (mbd.postProcessingLock) {
    
    
		if (!mbd.postProcessed) {
    
    
			try {
    
    
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
    
    
				...
			}
			mbd.postProcessed = true;
		}
	}
	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//从 java-doc 可以看出这里是 缓存对象来解决循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		...
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
    
    
		//完成属性填充
		//比如 A类里面有个 B,那么这个方法就是完成 B 的注入
		populateBean(beanName, mbd, instanceWrapper);
		//主要执行各种生命周期回调方法以及 AOP 等
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	...
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    
	// Make sure bean class is actually resolved at this point.
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    
    
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}

	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
    
    
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	if (mbd.getFactoryMethodName() != null) {
    
    
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same 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 {
    
    
			return instantiateBean(beanName, mbd);
		}
	}

	// Candidate constructors for autowiring?
	// 如果是自动装配,推断出各种候选的构造方法
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	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.
	//如果没有推断出合适构造方法,则使用默认的构造方法
	return instantiateBean(beanName, mbd);
}

Notice:createBeanInstance, as the name suggests, is to create an instance. At this time, the construction method has been executed, but here it is only to create an instance object, and it cannot be called a bean. Only when the object is put into the singleton pool can the entire life cycle be counted. Continue to look at the createBeanInstance
insert image description here
method

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//从 java-doc 可以看出这里是 缓存对象来解决循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		...
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

What is the assignment logic of the Boolean variable earlySingletonExposure? The above code shows that the three conditions are performed with && operation, and true will be returned only if they are satisfied at the same time;
1. mbd.isSingleton(); determine whether the currently instantiated bean is a singleton;Once again, the prototype does not support circular dependencies;Because if it is a prototype, it will return false here, because it is an && operation, the entire result is false;
2, this.allowCircularReferences; the entire global variable spring defaults to true; of course, spring provides an api for programmers to modify. In this case, true is also returned here

 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
 ac.setAllowCircularReferences(false); // 设置 false ,不支持循环引用
 ac.register(App.class);
 ac.refresh();
 System.out.println(ac.getBean("user"));

3. isSingletonCurrentlyInCreation(beanName); Determine whether the bean currently being created is in the collection of beans being created; as explained above, the singletonsCurrentlyInCreation collection currently exists and has only one user; so it will also return true;

That is, if earlySingletonExposure is true, it will enter the if condition judgment. Here comes the key point. Here is the key code to realize Spring's circular dependency. Spring's so-called three-level cache makes its debut.You will find that you just put the factory object into the singletonFactories collection, this step is also critical

/**
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    
    
	//singletonObjects 一级缓存
	//singletonFactories 二级缓存
	//earlySingletonObjects 三级缓存
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
    
    
		//如果 bean 存在单例池的话已经是一个完整的 bean 了,
		//也就是走完了生命周期,那就不需要后面的步骤了
		if (!this.singletonObjects.containsKey(beanName)) {
    
    
			//把工厂对象 put 到二级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			//?为什么要 remove,本质上看,这三个 map 存的都是同一个对象
			//Spring 的做法是三个不能同时都存
			//如果 singletonObjects 存了,其它两个就要 remove,反之亦然
			this.earlySingletonObjects.remove(beanName);
			//无关紧要这行
			this.registeredSingletons.add(beanName);
		}
	}
}

How does Spring resolve circular dependencies?

insert image description here
For example, the above two classes, User and Teacher, are injected into each other. By default, the default order of creating beans in spring is based on alphabetical order; that is to say, Teacher will be created first->start the life cycle of Teacher---->go to Teacher Attribute injection –> Fill User –> getBean(“user”) Get? –> Create User –> Start User’s life cycle –> Go to User attribute injection –> Fill Teacher –> getBean(“teacher”) get ?

So whether this dependency injection will go on indefinitely depends on whether getBean can be obtained, and the bottom layer of getBean calls the doGetBean method. Here is the code again:

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

	final String beanName = transformedBeanName(name);
	Object bean;
	// Eagerly check singleton cache for manually registered singletons.
	//第一次调用getSingleton: 因为是第一次初始化,这里 sharedInstance 显然是为 null,
	//里面的逻辑是实现循环依赖最主要的代码,后文详说
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
    
    
		....
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
    
    
		...
		try {
    
    
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			...
			// Create bean instance.
			if (mbd.isSingleton()) {
    
    
				//第二次调用getSingleton,完成了bean的初始化
				sharedInstance = getSingleton(beanName, () -> {
    
    
					try {
    
    
						return createBean(beanName, mbd, args);
					}
					...
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			else if (mbd.isPrototype()) {
    
    
				// It's a prototype -> create a new instance.
				...
			}
		}
		...
	}
	...
	return (T) bean;
}

There is no doubt that Spring solves the problem of circular dependency. According to the previous analysis, the first call to the getSingleton method works here. Enter the method to view

@Override
@Nullable
public Object getSingleton(String beanName) {
    
    
	return getSingleton(beanName, true);
}
/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
	//从单例池当(一级缓存)中直接拿,也就是文章里面'目前'的解释
	//这也是为什么getBean("xx")能获取一个初始化好bean的根本代码
	Object singletonObject = this.singletonObjects.get(beanName);
	//比如创建了 Teacher 对象,需要注入User,那么要创建 User,接着要把 teacher 注入到 user
	//根据前文分析,创建 Teacher 对象过程中,singletonCurrentlyInCreation 存了这个beanName
	//同理,创建 User 对象过程中,singletonCurrentlyInCreation 存了 user 这个beanName
	//并且二级缓存 singletonFactory 都保存了这两个工厂对象
	//进入if分支
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
		synchronized (this.singletonObjects) {
    
    
			//回顾一下文章上面的流程讲工厂对象那里,只把他存到了二级缓存,所以 singletonObject==nil
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
    
    
				//二级缓存中有值
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
    
    
					singletonObject = singletonFactory.getObject();
					//拿到了半成品的xbean之后,把他放到三级缓存;为什么?
					this.earlySingletonObjects.put(beanName, singletonObject);
					//然后从二级缓存清除掉x的工厂对象;为什么?
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

Why is it taken from the third-level cache first?

Mainly for performance, because an x ​​object is stored in the third-level cache, if it can be retrieved, it will not be searched at the second level; what is the use of the second level?

Why save the factory in the first place (secondary cache)? Why not directly save the L3 cache at the beginning?

As for the factory, you can change some states of the object. For example, the original use object factory is saved, but when I inject it, I need to change the properties or appearance of the object. This factory is more convenient.

Why remove from the second level cache?

Because if there are more complex circular dependencies, performance can be improved; for example, x, y, and z are mutually circularly dependent, then when y is injected into x for the first time, an x ​​is returned from the second-level cache through the factory and placed in the third-level cache, while the second When z is injected into x for the second time, there is no need to obtain the x object through the factory. Because the if branch first accesses the third-level cache; as for remove, it is for gc;

The difference between FactoryBean and BeanFactory

public interface FactoryBean<T> {
    
    
	//从工厂中获取bean
	@Nullable
	T getObject() throws Exception;
	//获取Bean工厂创建的对象的类型
	@Nullable
	Class<?> getObjectType();
	//Bean工厂创建的对象是否是单例模式
	default boolean isSingleton() {
    
    
		return true;
	}
}

  • Both of them are factories, but FactoryBean is essentially a Bean and is also managed by BeanFactory
  • BeanFactory is the top-level interface of the Spring container, and FactoryBean is more similar to a user-defined factory interface

Summarize the Spring Bean life cycle again

1. Scan, encapsulated into beandefination object, put into beandefination
2. Traverse map
3. Validate, is it abstract, lazy loading, or prototype
4. Obtain class
5. Infer construction method
5. Reflection, instantiate object
6. Merge beandefination
7. Expose a bean factory object in advance
8. Fill attributes, automatically inject: populateBean method
9. Execute part of the aware interface, call the declaration cycle initialization callback method (@postconstructor)
10. Complete the proxy if a proxy is needed
11. put Go to the singleton pool - the bean is completed - exists in the spring container

If it is @Resource --> call CommonAnnotationBeanPostProcessor
If it is @Autowire --> call AutowireAnnotationBeanPostProcessor

Guess you like

Origin blog.csdn.net/lhg_55/article/details/105371345
Recommended