Detailed SpringIOC: What surprises the interviewer is not the memorized eight-part essay, but the depth and breadth of the technology

interview questions

From the interviewer's torture from the depths of the soul: talk about your understanding of spring;

The inner activity of the confused job seeker: what? What is the specific problem? Are the interviews now out of the way? How do you ask me to answer such a big question?

The bewildered job seeker replied: Uh ~ ~ ~ this. . . . Uh~ ~ ~ that. . . . Amount ~ ~ ~ I don't know. . .

Why is the interviewer asking this kind of question?

It is undeniable that most of the current interview questions are like this. It is surprisingly similar. The interviewer likes to throw a question to see how deep you can talk. The test is your depth and breadth of this technology. Depth is your understanding of the underlying technology, breadth is the scope of application of this technology, and the direction of expansion.

At this time, a gangster classmate is about to ask: "Why do you need to know these low-level things? I only need to know how to use them. I always build rockets during interviews, but they make me screw screws during actual work." Although it is true, what you need to consider is that everyone can use this thing, and not only you. Since everyone knows something, what if it reflects your value? This needs to consider the depth. Xiaohong and Xiaoming both use spring, but Xiaoming knows its underlying execution mechanism and principle. It should be noted here that the depth of your answer determines your salary and treatment, which is very important. , how do we answer this question? In fact, it is very simple, first sort out the general context, and then explain it in depth one by one; I have written blogs like this since this year, and I will elaborate the explanation from the shallower to the deeper, and will give the code and flow chart.

As a programmer, if you want to develop in the direction of an expert, you must understand the idea of ​​programming, the underlying execution principle of the algorithm, and the code is the second, because there is only one principle, and there are various implementation methods. One interface allows 10,000 people To write the realization, the realization of ten thousand people will not be the same; this is the importance of thinking.

Spring IOC

First of all, before that, we must first know what ioc is. ioc is called inversion of control, and it can also be called dependency injection (DI). In fact, dependency injection is another term for ioc.

1. Who controls who? : In the past, the creation and destruction of objects were controlled by the user. After using ioc, the creation and destruction of objects are all controlled by the container. The user does not need to care about these, just focus on business needs;

2. What is reversal? : Since it is called reversal, there must be forward rotation. Forward rotation is actually the object looking for the instance, and the reverse rotation is reversed, so that the instance finds the object; how to find it? Through the container, of course!

3. Who depends on whom? : In the spring project, the object is understood as a bean, which can also be called a bean object. There is a dependency between the bean and the container. The creation of the bean object depends on the container, just like the child depends on the parent, and the child cannot give birth to himself. , requires the cooperation of parents to be born, the child here is the bean, and the parent is the container;

4. Who injects who? : The bean object is injected through the container, and this process is automated, that is to say, the container will automatically find a type instance that matches the bean object and inject it into the object;

The loading process of spring ioc

After understanding inversion of control and dependency injection, let's take a look at the loading process of ioc. The whole loading process of ioc is as shown in the figure below. First, look at the general process, and then go deeper (the yellow box is the comment content)

1. First, read the specified configuration file through BeanDefinitionReader to generate bean definition information, and then go to the complete bean definition information (BeanDefinition object). Note that only the definition information of the bean is stored here, and the bean object has not been instantiated; just like in the factory The same, the raw material is ready, but not yet produced, the raw material is the beanDefinition, and the production is the instantiation

2. Through a post-enhancer between the BeanDefinition and the complete BeanDefinition, the definition information of the bean can be modified uniformly. It only needs to implement the BeanFactoryPostProcessor interface. There can be multiple post-enhancers. A class that implements multiple BeanFactoryPostProcessors will then execute multiple times, like this:

package com.Spring.Boot.init;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
 * 扩展方法--后置增强器(可修改bean的定义信息)
 */
@Component
public class ExtBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//        BeanDefinition studentService = beanFactory.getBeanDefinition("studentService");
        System.out.println("扩展方法--可进行修改beanDefinition的定义信息");
    }
}
复制代码

3. After getting the complete BeanDefinition, you can create an object. This whole process is called the life cycle of a bean, which is the process from instantiation to destruction; Is there so much trouble? Isn't it enough to instantiate an object directly by reflection? Why is there initialization?"; First of all, this is a good question, come, let's give the applause to the student who asked the question; what I want to say is , even if an ordinary new object comes out, it will be instantiated and initialized in it. Next, we will focus on the life cycle of beans;

Spring Bean life cycle

Roughly speaking, the life cycle of beans is mainly divided into the following 4 steps

But in fact, it contains a lot of things inside, let's take a look at the refined flow chart;

how about it? Did you see a lot of things you haven't seen before? I seem to know a few, but most of them are stuff I haven’t seen before. It doesn’t matter if I don’t know. Next, we will explain them one by one.

Next, we will put 1, 3, and 4 together, because they are in the same interface, and the InstantiationAwareBeanPostProcessor interface can be implemented.

package com.Spring.Boot.init;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
 
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
 
    // 实例化前置
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        
        System.out.println("postProcessBeforeInstantiation被调用了----在对象实例化之前调用-----beanName:" + beanName);
        // 默认什么都不做,返回null
        return null;
    }
 
    // 实例化后置
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInstantiation被调用了---------beanName:" + beanName);
        //默认返回true,什么也不做,继续下一步
        return true;
    }
    
    // 属性修改
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("postProcessPropertyValues被调用了---------beanName:"+beanName);
        // 此方法可对bean中的属性值进行、添加、修改、删除操作;
        // 对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用,
        return pvs;
    }
}
复制代码

Below we explain in turn

1. Instantiate the front end

The InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class<?> beanClass, String beanName) method is used before the instantiation. There are two parameters in the method, namely beanClass and beanName. As the name implies, it is the class information of the bean object before the object is instantiated. To modify or expand to achieve the functions we want, its bottom layer is implemented by dynamic proxy AOP technology; and it is the first method to be executed in the bean life cycle;

Return non-null: The return value is of type Object, which means that we can return any type of value. Since the target object has not been instantiated at this time, this return value can be used to replace the instance of the target object that should have generated the object, and also That is to say, if a non-null value is returned, then when we need to use this bean in the future, we will get the object returned now, and we will not go to the second step to instantiate the object;

Returns an empty (null) value: the default is to return a null value, then return directly, and then call the doCreateBean method to instantiate the object;

2. Instantiate the object

The doCreateBean method creates an instance and uses reflection technology to create it. There is nothing to say about it. It is just equivalent to creating an object. However, it should be noted that at this time, the object is only instantiated, and the properties in the object have not been set;

3. Instantiate the post

方法名称: InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName)

Called after the target object is instantiated. At this time, the object has been instantiated, but the properties of the instance have not been set, and are all null. Because his return value is a factor in deciding whether to call the postProcessPropertyValues ​​method (because there is another factor that is mbd.getDependencyCheck());

Return false: If the method returns false and no check is required, then postProcessPropertyValues ​​will be ignored and not executed;

Returns true: If it returns true, postProcessPropertyValues ​​will be executed

4. Property modification

方法名称 :InstantiationAwareBeanPostProcessor.PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)

This method can modify the attribute value, and the scope of modification includes adding, modifying, and deleting operations; if the postProcessAfterInstantiation() method returns false after instantiation, this method will not be called;

5. Assign values ​​to user attributes

User attributes refer to the bean object attributes customized by spring people. Objects such as User, Student, Teacher, UserService, and IndexService are all custom bean objects. The fifth step is to assign values ​​to such attributes, using It is the AbstractAutowireCapableBeanFactory.populateBean() method to assign values;

6. Assign values ​​to container properties

The container properties are actually the properties that come with the container. These properties are all inherent in spring; it is certain that they are all implementation classes of the Aware interface. There are mainly the following implementation classes, and I have arranged their execution order. now,

Let's see how to use it first, and then explain the role of each Aware; the code above

package com.Spring.Boot.init.aware;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.*;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
import org.springframework.web.context.ServletContextAware;
import javax.servlet.ServletContext;
 
@Component
public class AllAwareInterface  implements BeanNameAware, BeanClassLoaderAware,
        BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware,
        ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,
        ApplicationContextAware, ServletContextAware, LoadTimeWeaverAware, ImportAware {
 
    @Override
    public void setBeanName(String name) {
        // BeanNameAware作用:让Bean对Name有知觉
        //这个方法只是简单的返回我们当前的beanName,听官方的意思是这个接口更多的使用在spring的框架代码中,实际开发环境应该不建议使用
        System.out.println("1 我是 BeanNameAware 的 setBeanName 方法  ---参数:name,内容:"+ name);
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("2 我是 BeanClassLoaderAware 的 setBeanClassLoader 方法");
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // 注意: 如果使用 @Configuration 注解的话,setBeanFactory方法会执行2次,
        System.out.println("3 我是 BeanFactoryAware 的 setBeanFactory 方法");
    }
    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("4 我是 EnvironmentAware 的 setEnvironment 方法");
    }
    @Override
    public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
        System.out.println("5 我是 EmbeddedValueResolverAware 的 setEmbeddedValueResolver 方法");
    }
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("6 我是 ResourceLoaderAware 的 setResourceLoader 方法");
    }
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("7 我是 ApplicationEventPublisherAware 的 setApplicationEventPublisher 方法");
    }
    @Override
    public void setMessageSource(MessageSource messageSource) {
        System.out.println("8 我是 MessageSourceAware 的 setMessageSource 方法");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("9 我是 ApplicationContextAware 的 setApplicationContext 方法");
    }
    @Override
    public void setServletContext(ServletContext servletContext) {
        System.out.println("10 我是 ServletContextAware 的 setServletContext 方法");
    }
    @Override
    public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
        //LoadTimeWeaver 简称LTW,LTW是AOP的一种实现方式,此方法是为了获取Aop织入的对象,使用的织入方式是:类加载期织入,
        // 一般的aop都是运行期织入,就是在运行的时候才进行织入切面方法,但是LTW是在类加载前就被织入了,也就是class文件在jvm加载之前进行织入切面方法
        // 只有在使用 @EnableLoadTimeWeaving 或者存在 LoadTimeWeaver 实现的 Bean 时才会调用,顺序也很靠后
        System.out.println("11 我是 LoadTimeWeaverAware 的 setLoadTimeWeaver 方法");
    }
    @Override
    public void setImportMetadata(AnnotationMetadata annotationMetadata) {
        //只有被其他配置类 @Import(XX.class) 时才会调用,这个调用对 XX.class 中的所有 @Bean 来说顺序是第 1 的。
        System.out.println("12 我是 ImportAware 的 setImportMetadata 方法");
    }
}
复制代码

Some of the results printed on the console after starting spring are as follows:

You can see that their output results are printed in order, which is its standard order; next, let's understand their specific functions

6.1 BeanNameAware.setBeanName ()

This method simply returns our current beanName. The official meaning is that this interface is more used in spring's framework code, and the actual development environment should not be recommended.

6.2 BeanClassLoaderAware.setBeanClassLoader()

Get the class loader of the bean,

6.3 BeanFactoryAware.setBeanFactory()

Get the bean factory. The beanFactory allows you to read the objects in the IOC container at will without relying on the injection method, but the beanFactory itself still needs to be injected.

It should be noted that in general, we use the @Component annotation. If the @Configuration annotation is used, the setBeanFactory method will be executed twice;

6.4 EnvironmentAware.setEnvironment()

After implementing the EnvironmentAware interface and rewriting the setEnvironment method, the property values ​​configured in the configuration files of application.properties, xml, and yml can be obtained when the project is started.

6.5 EmbeddedValueResolverAware.setEmbeddedValueResolver ()

Usually we use the @Value annotation to get the values ​​in the properties and yml files. It is also very cumbersome to use @Value in each class. It is much more convenient after implementing the EmbeddedValueResolverAware interface. The usage is the same as @Value, it needs to be wrapped in ${};

@Component   
public class PropertiesUtil implements EmbeddedValueResolverAware {
 
	@Override
	public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {   
     System.out.println(stringValueResolver.resolveStringValue("${logging.file}"));
	}
}
复制代码

6.6 ResourceLoaderAware.setResourceLoader()

Spring ResourceLoader provides us with a unified getResource() method to retrieve external resources through the resource path. There are different implementations of loading resources or files (such as text files, XML files, properties files or image files) into the Spring application context. In fact, it is used to load external resources; there is a parameter in the method: ResourceLoader, This parameter is actually ApplicationContext (spring's context object); it can be directly forced;

package org.crazyit.app.service;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
public class TestBean implements ResourceLoaderAware{
   
    public void setResourceLoader(ResourceLoader resourceLoader) {
        // 可直接强转为 ApplicationContext
        ApplicationContext context = (ApplicationContext) resourceLoader;
 
        System.out.println("6 我是 ResourceLoaderAware 的 setResourceLoader 方法");
    }
   
}
 
复制代码

and we can specify different prefixes to create paths to load resources from different locations

6.7 ApplicationEventPublisherAware.setApplicationEventPublisher();

ApplicationEventPublisherAware is an event publisher interface. Using this interface, our own Service has the ability to publish events. After the user registers, instead of calling other business services, a user registration event is published. So here is the publishing event, then there must be an interface for monitoring events. This interface is called ApplicationListener. As long as the ApplicationListener interface is implemented, the published events can be accepted. Next, we will write an example to simulate publishing events and listening events;

First create an entity class to store the published event content StringEvent.java

package com.Spring.Boot.init.listener.eventModel;
import org.springframework.context.ApplicationEvent;
//事件监听对象
public class StringEvent extends ApplicationEvent {
 
    private String str;
    // 构造函数
    public StringEvent(Object source) {
        super(source);
        str = source.toString();
    }
    // 获取字符串
    public String getStr(){
        return str;
    }
}
复制代码

Create a class that publishes events: ExtApplicationEventPublisherAware.java , implement the ApplicationEventPublisherAware interface to increase the function of publishing events;

package com.Spring.Boot.init.aware;
 
import com.Spring.Boot.init.listener.eventModel.StringEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
 
/**
 * 发布事件
 */
@Component
public class ExtApplicationEventPublisherAware implements ApplicationEventPublisherAware {
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        System.out.println("发布事件,事件对象为 StringEvent ,内容为 :1234");
        StringEvent stringEvent = new StringEvent("1234");
        // 发布事件 ,发布后会在 ApplicationListener.onApplicationEvent()方法进行捕获;
        applicationEventPublisher.publishEvent(stringEvent);  // 发布事件
    }
}
复制代码

Create an event listener: EventListener.java to listen to all published events;

package com.Spring.Boot.init.listener;
 
 
import com.Spring.Boot.init.listener.eventModel.StringEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
 
//事件监听器
@Component
public class EventListener implements ApplicationListener<StringEvent> {
 
    @Override
    public void onApplicationEvent(StringEvent o) {
        System.out.println("监听到事件,内容:"+o.getStr());
    }
}
复制代码

Next, run the spring project and see the printed results as follows. At this point, the event publishing and monitoring are completed;

6.8 MessageSourceAware.setMessageSource()

Internationalized message notification operations

6.9 ApplicationContextAware.setApplicationContext()

ApplicationContextAware is mainly used to obtain the ApplicationContext context globally. ApplicationContext is actually a container. For this reason, we can implement the ApplicationContextAware interface to obtain the ApplicationContext container object; we can make it a public static class, so that we can take it anywhere we want.

package com.Spring.Boot.init.aware;
 
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
 
@Component
public class ExtApplicationContextAware implements ApplicationContextAware {
 
    /**
     * Spring容器会在加载完Spring容器后调用ApplicationContextAware.setApplicationContext方法
     * ApplicationContextAware 主要用来全局获取 ApplicationContext 上下文,
     */
 
    private static ApplicationContext applicationContext;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (ExtApplicationContextAware.applicationContext == null) {
            ExtApplicationContextAware.applicationContext = applicationContext;
        }
        System.out.println("========ApplicationContext配置成功========");
        System.out.println("========在普通类可以通过调用SpringBootBeanUtil.getApplicationContext()获取applicationContext对象========");
        System.out.println("========applicationContext="+ ExtApplicationContextAware.applicationContext +"========");
    }
 
    /**
     * 获取applicationContext
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    /**
     * 通过name获取 Bean.
     * @param name
     * @return
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
 
    /**
     * 通过class获取Bean.
     * @param clazz
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }
 
    /**
     * 通过name,以及Clazz返回指定的Bean
     * @param name
     * @param clazz
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
 
}
复制代码

Of course, it can also be injected directly, like this:

    @Autowired
    private ApplicationContext applicationContext;
复制代码

6.10 ServletContextAware.setServletContext()

By implementing the ServletContextAware interface, the servletContext, which is the context of the servlet, can be obtained;

What is ServletContext: When the WEB container starts, it will create a corresponding ServletContext object for each WEB application, which represents the current web application. The reference of the ServletContext object is maintained in the ServletConfig object. When developers write servlets, they can obtain the ServletContext object through the ServletConfig.getServletContext method.

Since all servlets in a WEB application share the same ServletContext object, communication between servlet objects can be achieved through the ServletContext object. The ServletContext object is also commonly referred to as the context domain object.

6.11 LoadTimeWeaverAware.setLoadTimeWeaver ()

In fact, there are still 2 unprinted during debugging. The 11th is LoadTimeWeaver, referred to as LTW. LTW is an implementation of AOP. This method is to obtain the objects woven by Aop. The weaving method used is: class Loading time weaving, general aop is run time weaving, that is, weaving the aspect method at runtime, but LTW is woven before the class is loaded, that is, the class file is woven before the jvm is loaded. The entry method is called only when @EnableLoadTimeWeaving is used or when there is a bean implemented by LoadTimeWeaver, and the order is very late;

6.12 ImportAware.setImportMetadata()

Another thing that is not printed is the ImportAware interface. The methods of this interface will only be called when other configuration classes @Import(XX.class) are called. This call is the first order for all @Beans in XX.class.

7. Initialize the front

Method name: BeanPostProcessor.postProcessBeforeInitialization()

The method to execute before each bean is initialized (as many beans as how many times)

Note: After this method is enabled, the method annotated with @PostConstruct will be invalid

8. Initialize the post

Method name: BeanPostProcessor.postProcessAfterInitialization ()

The method to execute after each bean is initialized (as many beans as how many times)

The implementation code of initialization pre- and post-initialization is as follows

package com.Spring.Boot.init;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
 
@Component
public class ExtBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在每一个 Bean 初始化之前执行的方法(有多少 Bean 调用多少次)
        // 注意 : 启用该方法后,标注了@PostConstruct注解的方法会失效
        System.out.println("初始化前置方法");
        return null;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
         在每一个 Bean 初始化之后执行的方法(有多少 Bean 调用多少次)
        System.out.println("初始化后置方法");
        return null;
    }
}

复制代码

9. Execute the initialization method

There are three initialization methods, namely the method of adding the @PostConstruct annotation, implementing the InitializingBean interface, and adding the initMethod attribute to the @bean annotation; we will talk about them one by one.

10. Initialization method 1: @PostConstruct

After adding the @PostConstruct annotation to the bean object, the initialization function can be realized. The method modified by @PostConstruct will run after the constructor and before the init() method. If there are more than one, it will be executed multiple times;

Note: If spring implements the postProcessBeforeInitialization() method of the BeanPostProcessor interface, which is the initial post method of 12, then the @PostConstruct annotation will be invalid;

code example

package com.Spring.Boot.init;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
 
// @PostConstruct注解
@Component
public class ExtPostConstruct {
 
    /**
     * 被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。如果有多个则会执行多次
     * 注意: 如果spring 实现了 BeanPostProcessor接口的postProcessBeforeInitialization方法,该@PostConstruct注解会失效
     */
    @PostConstruct
    public void init() {
        System.out.println("第一个init...");
    }
 
    // 有多个会执行多次
    @PostConstruct
    public void init1() {
        System.out.println("第二个init1...");
    }
 
}

复制代码

11、InitializingBean.afterPropertiesSet()

One of the spring initialization methods is to perform custom initialization behavior after the BeanFactory completes the property setting.

Execution order: before initMethod, after @PostConstruct

code example

package com.Spring.Boot.init;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
 
@Component
public class ExtInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        // 一个 InitializingBean 执行一次
        // spring 初始化方法,作用是在BeanFactory完成属性设置之后,执行自定义的  初始化行为.
        // 执行顺序:在initMethod之前执行,在@PostConstruct之后执行
        System.out.println("InitializingBean");
    }
}

复制代码

12、init-method

The bean configuration file attribute init-method is used to specify the execution method when the bean is initialized, instead of inheriting the InitializingBean interface,

One thing to note is that the initialization method can only be used after a complete instance of the class has been created.

Example code, first define a class: BeanTest.java , define an initialization method initMethod_1() in the class

package com.Spring.Boot.init.bean;
 
public class BeanTest {
    
    // 将要执行的初始化方法
    public void initMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
}

复制代码

xml configuration method

<bean id="beanTest" class="com.BeanTest" init-method="init"></bean> annotation configuration method

package com.Spring.Boot.init;
import com.Spring.Boot.init.bean.BeanTest;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component()
public class InitMethod  {
    
    // 在@Bean注解上添加initMethod属性,指向类中的 initMethod_1 执行初始化方法
    @Bean(initMethod = "initMethod_1")
    public BeanTest getBeanTest(){
        return new BeanTest();
    }
}
复制代码

13. In use

At this point, the bean object has been completely created, is a complete object, and is being used by other objects;

14. Destruction process

It needs to be said first that the beans managed by the spring container are singleton by default, and there is a @Scope annotation on the class by default, which is like this

package com.Spring.Boot.init;
 
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
@Component()
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
// @Scope(value = "singleton")  // 也可以这样写
public class InitMethod  {
 
  // methods....
 
}
复制代码

If you want to set up multiple instances, you only need to change the property value of @Scope. Just like this, the multiple instance mode is also called the prototype mode. The bottom layer is not to recreate a bean object, but to use deep copy technology. It is to copy an object and use it

@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
// @Scope(value = "prototype") // 也可以这样写
复制代码

Why introduce singleton and multiple instances? Because ah, the direction of the destruction process is related to whether you are single or multiple;

If it is a singleton mode, the DisposableBean.destroy() method will be executed first, and then the destroy-Method method will be executed;

14.1 DisposableBean.destroy()

Destruction method of singleton mode, sample code

package com.Spring.Boot.init.destroy;
 
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Component;
 
/**
 * 销毁方法
 */
@Component
public class ExtDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("我被销毁了");
    }
}
复制代码

When the main method ends, the result printed on the console is as follows

14.2 destory-method method

Let's take the example of the 11th process, but this time we add the destroyMethod attribute to the @Bean annotation, pointing to the destroy method: destroyMethod_1()

package com.Spring.Boot.init;
 
import com.Spring.Boot.init.bean.BeanTest;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
 
@Component()
public class InitMethod  {
 
    // 在@Bean注解上添加initMethod属性,指向类中的 initMethod_1 执行初始化方法
    // 在@Bean注解上添加destroyMethod属性,指向类中的 destroyMethod_1 执行销毁方法
    @Bean(initMethod = "initMethod_1",destroyMethod = "destroyMethod_1")
    public BeanTest getBeanTest(){
        return new BeanTest();
    }
}
BeanTest.java

package com.Spring.Boot.init.bean;
 
public class BeanTest {
 
    // 将要执行的初始化方法
    public void initMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
 
    // 将要执行的销毁方法
    public void destroyMethod_1(){
        System.out.println("我是beanTest的init方法");
    }
 
 
}
复制代码

xml configuration

<bean id="beanTest" class="com.BeanTest" destroy-method="destroyMethod_1"></bean>

15. Return the bean to the user, and the rest of the life cycle is controlled by the user

Because spring cannot manage in the multi-instance mode, the life cycle is handed over to the user to control. After the user runs out of bean objects, the java garbage processor will automatically recycle the useless objects;


Author: Java Architect
Link: https://juejin.cn/post/6966158157202587662
Source: Rare Earth Nuggets
The copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

Guess you like

Origin blog.csdn.net/wdjnb/article/details/124295494
Recommended