spring中bean的生命周期
上一个小节梳理了一下Spring Boot的依赖注入的基本知识,今天来梳理一下spring中bean的生命周期。
下面,让我们一起看看bean在IOC容器中是怎么被创建和销毁的。
bean的生命周期大致分为四个部分:
bean的定义和初始化
大致流程如下:
默认情况下,spring会在启动时完成对bean的定义、发布以及初始化,但是,有时候我们并不想让spring在启动时就完成bean的初始化,更想的是在我们用到它时,才去完成初始化的动作,最常见的就是循环依赖的场景了。
而解决这个问题就需要用到spring的延迟初始化的机制了。
spring的延迟初始化bean机制
可以使用2中方法使bean进行延迟初始化:
@ComponentScan注解的lazyInit属性
@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"},lazyInit = true)
设置该属性为true后,对应的扫描规则下的bean都会进行延迟初始化
@Lazy注解
该注解用于指定某一个依赖的bean进行延迟初始化,用法如下:
@Autowired
@Lazy
private Animal cat;
bean的初始化生命周期的各个阶段
好了,现在我们正式看看bean的生命周期的各个阶段,如下图所示:
这个流程介绍了bean从初始化到销毁的过程。
注意:流程中的setApplicationContext方法有些特殊,即使你定义了 ApplicationContextAware 接口,但是有时候并不会调用,这要根据你的 IoC器来决定。 我们知道, Spring IoC 容器最低的要求是实 BeanFactory 接口,而不是ApplicationContext 接口, 对于那些没有实现 Application Cont xt 接口的容器 ,在生命周期对应的 ApplicationContextAware 定义的方法也是不会被调用的,只有实现了 Applic ationContext 接口的容器,才会在生命周期调用 ApplicationContextAware 定义的 setApplicationContext
方法。
接下来,让我们一起测试一下bean的生命周期。
首先创建一个类,同时让它实现流程中的这些接口,代码如下:
@Component
@Slf4j
public class BeanLifePeriod implements BeanNameAware, BeanFactoryAware, ApplicationContextAware
, InitializingBean, DisposableBean {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
log.warn("【{}】调用了BeanFactoryAware的setBeanFactory",this.getClass().getSimpleName());
}
@Override
public void setBeanName(String name) {
log.warn("【{}】调用了BeanNameAware的setBeanName",this.getClass().getSimpleName());
}
@Override
public void destroy() throws Exception {
log.warn("【{}】调用了DisposableBean的destroy",this.getClass().getSimpleName());
}
@PreDestroy
public void destroyMyself() {
log.warn("【{}】调用了注解@PreDestroy定义的自定义销毁方法",this.getClass().getSimpleName());
}
@Override
public void afterPropertiesSet() throws Exception {
log.warn("【{}】调用了InitializingBean的afterPropertiesSet",this.getClass().getSimpleName());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.warn("【{}】调用了ApplicationContextAware的setApplicationContext",this.getClass().getSimpleName());
}
@PostConstruct
public void init(){
log.warn("【{}】调用了注解@PostConstruct定义的自定义初始化方法",this.getClass().getSimpleName());
}
}
因为BeanPostProcessor接口的方法是针对于所有的bean的,所以我们这里单独创建一个类来实现它:
@Component
@Slf4j
public class BeanPostProcessorExample implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.warn("BeanPostProcessor调用postProcessBeforeInitialization方法,参数【{},{}】"
, bean.getClass().getSimpleName(), bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.warn("BeanPostProcessor调用postProcessAfterInitialization方法,参数【{},{}】"
, bean.getClass().getSimpleName(), bean);
return bean;
}
}
接下来,创建ioc配置类和测试类
@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"})
@Configuration
@Slf4j
public class LifePeriodAppConfig {
}
public class IocBeanLifePeriod {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifePeriodAppConfig.class);
context.close();
}
}
运行main方法,可以看到如下日志:
上面的流程可用于自定义的bean,但是有时候bean不是我们自己定义的,而是第三方的bean,那怎么办呢?
在小节全注解下的IOC中我们介绍了@Bean注解,它可以用来向容器发布第三方的bean,所以通过它,我们也可以自定义初始化和销毁的方法,用法如下:
@ComponentScan(basePackages = {"com.zzm.iocbeanlifeperiod"})
@Configuration
@Slf4j
public class LifePeriodAppConfig {
@Bean(value = "lifePeriodUser",initMethod = "init",destroyMethod = "destroy")
public LifePeriodUser getUser(){
return new LifePeriodUser().setId(3L).setUserName("Bean手动注入").setNote("Bean手动注入");
}
}
@Data
@Accessors(chain = true)
@Slf4j
public class LifePeriodUser {
private Long id;
private String userName;
private String note;
public void init(){
log.warn("【{}】调用了自定义用户初始化方法",this.getClass().getSimpleName());
}
public void destroy(){
log.warn("【{}】调用了自定义用户销毁方法",this.getClass().getSimpleName());
}
}
感兴趣的小伙伴可以自己尝试下,今天就到这里了。。。。。