一般情况下,我们只是关心如何正确地将Bean装配到容器中,并不关心Ioc容器是如何装配和销毁Bean的过程。但是恰恰有时候,我们需要自定义初始化或销毁Bean的过程,以满足一些“特殊的”需求。比如,数据源在关闭的时候调用其close方法,这是项目开发过程中很常见的需求。
Bean的生命周期大致可以分为4个部分:
1. Bean的定义
2. Bean的初始化
3. Bean的生存期
4. Bean的销毁
Bean的定义
-
资源定位的过程。
如使用@ComponentScan定义的扫描路径去找@Component的类(PS:现在启动类@SpringBootApplication会直接扫描本包内的@Compnent注释的类) -
解析资源并保存定义。
-
Spring IoC容器装载Bean定义。
(PS:此时还是没有实例化Bean)
Bean的生命周期
完成了以上三步,还没有实例化的生成,更没有完成依赖注入。默认情况下,Spring会继续完成Bean的实例化和依赖注入。
但是在某些情况下,我们希望Spring 在装载Bean之后,不采取自动实例化和依赖注入,而是在我们要取出这个Bean的时候再执行初始化等操作。
ComponentScan中还有一个配置项lazyInit,默认值为false,就是说不会延迟初始化。但我们将其配置为true时,将会执行延迟初始化。但在spring boot中,这个配置项目即使配置了也可能无效,具体看下面的方法。
- 解析Bean定义后会将定义保存在BeanDefinition实例中。
- 依赖注入例如@Autowired注入的资源。
- 默认情况下,在Spring IoC容器初始化的时候,Bean将会自动实例化和注入。如果不想跟随Ioc容器初始化,在Spring web开发中可以通过以下步骤进行延迟加载(缺少一个都不能实现):
- 首先在对应实体类上面加上@Lazy注解。
- 然后在@Autowired注解引用该Bean的地方同时再加上@Lazy注解。
- 使用@Bean注入的地方(如果有)也要加上@Lazy。
接口BeanNameAware
Spring容器在初始化和销毁Bean之前,会自动回调BeanNameAware中的setName方法。
接口BeanFactoryAware
Spring容器会继getName方法后自动回调BeanFactoryAware中的setBeanFactory方法。
接口ApplicationContextAware
需要容器实现ApplicationContext接口才会被调用。ApplicationContext是BeanFactory的子接口,BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean时才实例化目标Bean。而ApplicationContext在初始化上下文时就实例化所有单实例的Bean。基于注解配置的应用上下文的IoC容器实现了AnnotationConfigApplicationContext,它就是ApplicationContext接口的一个实现类,默认实例化DefaultListableBeanFactory工厂。
示范Bean:
@Component
@Data
public class Animal implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
private String name;
private Integer age;
private String cry;
@Override
public void setBeanName(String name) {
System.out.println("Animal被赋予了姓名:" + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Animal被工厂创建了出来:" + beanFactory.getClass().getName());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("加载容器环境中:" + applicationContext.getClass().getName());
}
}
控制台输出:
Animal被赋予了姓名:animal
Animal被工厂创建了出来:org.springframework.beans.factory.support.DefaultListableBeanFactory
加载容器环境中:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
接口BeanPostProcessor
接口代码:
public interface BeanPostProcessor {
//bean初始化方法调用前被调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//bean初始化方法调用后(即afterPropertiesSet方法后)被调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
这个接口的方法改写,会对该容器中所有的bean都生效。
@PostConstruct
写上这个注释的方法就是自定义初始化方法了,没什么好说的。
接口InitializingBean
继承该接口后,再实现afterPertiesSet方法。到此实例化完成,进入生存期。
接口BeanPostProcessor
回调postProcessAfterInitialization方法。针对所有Bean有效。
@PreDestory
写上这个注释的方法就是自定义销毁方法了,没什么好说的。
接口DisableBean
继承该接口,再实现dstory方法。到这里,Spring中一个Bean的生命周期结束了。
只要继承、使用了以上任意接口或注解,延迟加载的配置将会失效。
demo项目地址:项目地址