Normal bean initialization is performed during the container-initiated initialization phase, whereas lazy-init-modified beans are triggered when context.getBean(” “) is called for the first time from the container.

When Spring starts, it parses all bean information (including XML and annotations) into a BeanDefinition that Spring recognizes and stores it in a Hashmap for subsequent initialization.

Each BeanDefinition is then processed, if lazily loaded it is not processed during container initialization, and others are initialized and dependency injected during container initialization. I’ve talked a lot about Spring container initialization and bean initialization in this article. Container initialization may include bean initialization depending on whether the bean is lazily loaded or not.

One. Sneak peek

To see what this property does, we define a plain bean called coffee. The code looks like this:

1. Demo of ordinary non-lazy-loaded beans

package com.test.spring; Public class Coffee {public Coffee() {system.out.println (" initializing bean!! Call the no-argument constructor "); }}Copy the code
<bean name="coffee" class="com.test.spring.Coffee"/>
Copy the code
@test public void testLazyInit() {system.out.println (" Start to initialize the Spring container "); // Non-lazy-loaded beans are initialized when the container is initialized, Will take the Spring behind the startup of the source code analysis ApplicationContext context = new ClassPathXmlApplicationContext (" Spring - beans. XML "); // The constructor for a non-lazy-loaded bean will print system.out.println ("Spring container initialized ") at this location; System.out.println(" Start getting Bean from container "); Coffee coffee = context.getBean("coffee", Coffee.class); System.out.println(" getbean :" + coffee); }Copy the code

The running results are as follows:

2. Demonstration of non-lazy-loaded beans

<bean name="coffee" class="com.test.spring.Coffee" lazy-init="true" />
Copy the code
@test public void testLazyInit() {system.out.println (" Start to initialize the Spring container "); / / in the initialization phase of container not initialized for lazy loading bean ApplicationContext context = new ClassPathXmlApplicationContext (" spring - beans. XML "); System.out.println("Spring container initialization completed "); System.out.println(" Start getting Bean from container "); Coffee = context.getBean(" Coffee ", coffee.class); Coffee = context.getbean (" Coffee ", Coffee. System.out.println(" getbean :" + coffee); }Copy the code

The running results are as follows:

Two, principle analysis

Spring does two things when it starts up:

Initialize the container. 2. Initialize the bean and dependency injection. (Lazy-loaded beans do not do the second.) But for most beans, bean initialization and dependency injection occur during container initialization, only lazy-loaded beans are initialized and dependency injected when the application first executes a getBean. The Spring container initialization code is as follows:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
Copy the code
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); Ioc refresh() {// Spring ioc refresh(); }}Copy the code

Refresh Spring initialization entry refresh Spring initialization entry refresh

[public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);  try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory);  // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);  // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Instantiate all remaining (non-lazy-init) singletons. // Instantiate all remaining (non-lazy-init) singletons !!!!  finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } }](http://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247492186&idx=3&sn=cbb8fda8f97f28a24939134e711b51a9&chksm=eb506 76cdc27ee7afead02ae8c3c0fb6611681c119fa0b3f6dac238676aeb2660a9d77dde392&scene=21#wechat_redirect)Copy the code

Line 20 is relevant to this topic, which says that only non-lazy-init beans are handled when the container is started, Lazy loading of bean in the Spring startup doesn’t do any processing and look at the source code below will understand the point in line 20 finishBeanFactoryInitialization initialization (the beanFactory) in a non – lazy – init function of beans PreInstantiateSingletons () the logic is as follows

1. Iterate through the beanNames collection to get each BeanDefinition

2. Check whether the bean is lazily loaded, if not, continue processing (non-lazy-init bean does not process)

3. Check whether it is a FactoryBean. If not, instantiate it and inject it

Public void preInstantiateSingletons() throws BeansException {// All beanDefinition set List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // Trigger the initialization of all non-lazy-loaded singleton beans for (String beanName: BeanNames) {/ / get bean definitions RootBeanDefinition bd = getMergedLocalBeanDefinition (beanName); // Check if the bean is lazily loaded, if it is singleton and not lazily loaded then in the Spring container if (! bd.isAbstract() && bd.isSingleton() && ! Bd.islazyinit ()) {if (isFactoryBean(beanName)) {final FactoryBean<? > factory = (FactoryBean<? >) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() ! = null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<? >) factory).isEagerInit(); } }, getAccessControlContext()); }}else {// Initialize dependency injection if it is a normal bean, GetBean (beanName) then fires the same logic as // Context.getBean ("beanName"); }}}}Copy the code

The getBean() method is a function that implements bean initialization and dependency injection

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

Third, summary

For beans that are decorated lazy-init the Spring initialization phase does not init and dependency injection, when the first getBean is initialized and dependency injection for beans that are not lazy-loaded the getBean is fetched from the cache because the container initialization phase has already been initialized

/ / container startup initialization will initialize and dependency injection of lazy loading bean ApplicationContext context = new ClassPathXmlApplicationContext (" spring - beans. XML "); Coffee = context.getbean (" Coffee ", coffee.class);Copy the code

Source: Xiao Mu’s blog

www.cnblogs.com/wyc1994666/…