上一篇 Spring Boot IoC(四)依赖注入DI
之前的Ioc学习中,我们只是关心如何正确的将Bean装配到Ioc容器中,而没有关心IoC容器如何装配和销毁bean的过程。有时候我们也需要自定义初始化或者销毁Bean的过程,以满足一些Bean的特殊初始化和销毁的要求。为了解决这些问题,我们有必要了解Spring Ioc初始化和销毁Bean的过程,这边是Bean的生命周期的过程。它大致分为Bean定义,bean初始化,bean的生存期和bean的销毁4个部分。
先看前3步:
完成这3步只是一个资源定位并将Bean的定义发布到Ioc容器的过程。还没有Bean实例的成成,更没有依赖注入。在默认情况下,spring会如图所示去完成bean的实例化和依赖注入,这样从Ioc容器中就可以得到一个依赖注入完成的bean。但是,有些bean会受到变化因素的影响,这时候我们到希望是取出bean的时候完成初始化和依赖注入,换句话说就是让那些bean只是将定义发布到ioc容器而不做实例化和依赖注入,当我们取出来的时候才做初始化和依赖注入操作。
@Component
中有一个配置像lazyInit
,默认为false,不进行延迟初始化。因此在默认的情况下spring会对bean进行实例化和依赖注入对应的属性值。
我们首先定义两个接口和实现类
Shoes接口(需要注入的接口)
package com.lay.ioc.pojo.definiion;
public interface Shoes {
public void put();
}
Person接口
package com.lay.ioc.pojo.definiion;
public interface Person {
public void activity();
public void setShoes(Shoes shoes);
}
Shoes接口实现类BasketShoes
package com.lay.ioc.pojo;
import org.springframework.stereotype.Component;
import com.lay.ioc.pojo.definiion.Shoes;
@Component
public class BasketShoes implements Shoes{
@Override
public void put() {
System.out.println("穿篮球鞋【"+BasketShoes.class.getSimpleName()+"】去打球");
}
}
Person实现类Programmer
@Component
public class Programmer implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private Shoes shoes = null;
@Override
public void activity() {
this.shoes.put();
}
@Override
@Autowired
@Qualifier("basketShoes")
public void setShoes(Shoes shoes) {
System.out.println("延迟依赖注入");
this.shoes = shoes;
}
}
这里我们在setShoes方法里打印一句话
AppConfig配置类
package com.lay.ioc.config;
/**
* @ComponentScan 标明会进行扫描
* @author Lay
*/
@ComponentScan(basePackages= {"com.lay.ioc.*"})
@EnableAutoConfiguration
@Configuration
public class AppConfig {
}
测试类
package com.lay.ioc.config;
public class IoCTest {
private static Logger log = LoggerFactory.getLogger(IocApplication.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
Person person=ctx.getBean(Programmer.class);//在这里打断点进行调试查看
person.activity();
ctx.close();
}
}
我们在测试类的getBean方法上打断点,启动调试,会发现我们还并没有获取bean的实例,而日志就已经打印出了我们打印的语句,可见它是在ioc容器初始化时就执行了实例化和依赖注入。
为了改变这个情况,我们在配置类AppConfig加入lazyInit配置
package com.lay.ioc.config;
/**
* @ComponentScan 标明会进行扫描
* @author Lay
*/
@ComponentScan(basePackages= {"com.lay.ioc.*"},lazyInit=true)
@EnableAutoConfiguration
@Configuration
public class AppConfig {
}
然后进行测试,就会发现我们输出的语句“延迟依赖注入”并没有出现在控制台日志中。只有运行过断点处才会出现。这就是我我们把它修改为了延迟初始化。spring并不会在发布bean定义后马上为我们完成实例化和依赖注入。
如果仅仅是实例化和依赖注入还是比较简单的,还不能完成进行自定义的要求。为了完成依赖注入的功能,spring在依赖注入之后,还提供了一系列的接口和配置来完成bean的初始化的过程。
图中描述的是整个ioc容器初始化bean的过程。
我们对Programmer
进行改造模拟Bean的生命周期
Programmer
package com.lay.ioc.pojo;
@Component
public class Programmer implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
//@Autowired
private Shoes shoes = null;
@Override
public void activity() {
this.shoes.put();
}
@Override
@Autowired
@Qualifier("basketShoes")
public void setShoes(Shoes shoes) {
System.out.println("延迟依赖注入");
this.shoes = shoes;
}
@Override
public void setBeanName(String name) {
System.out.println("【"+this.getClass().getSimpleName()+"】调用BeanNameAware的setBeanName()方法");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("【"+this.getClass().getSimpleName()+"】调用BeanFactoryAware的setBeanFactory()方法");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("【"+this.getClass().getSimpleName()+"】调用ApplicationContextAware的setApplicationContext()方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("【"+this.getClass().getSimpleName()+"】调用InitializingBean的afterPropertiesSet()方法");
}
@PostConstruct
public void init() {
System.out.println("【"+this.getClass().getSimpleName()+"】调用注解@PostConstruct定义的自定义初始化方法");
}
@PreDestroy
public void destroy1() {
System.out.println("【"+this.getClass().getSimpleName()+"】调用 注解@PreDestroy定义的自定义销毁方法");
}
@Override
public void destroy() throws Exception {
System.out.println("【"+this.getClass().getSimpleName()+"】调用DisposableBean的destroy()方法");
}
}
这样,这个Bean就实现了生命周期中单个Bean可以实现的所有接口,并且通过注解@PostConstruct
定义了初始化方法,通过注解@PreDestroy
定义了自定义销毁方法。为了测试Bean的后置处理器,我们创建一个类BeanPostProcessorDemo
来实现BeanPostProcessor
,方法是针对所有Bean都生效的。
package com.lay.ioc.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class BeanPostProcessDemo implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcess调用postProcessBeforeInitialization()方法,参数【"+bean.getClass().getSimpleName()+"】 【"+beanName+"】");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcess调用postProcessAfterInitialization()方法,参数【"+bean.getClass().getSimpleName()+"】 【"+beanName+"】");
return bean;
}
}
注意,这个Bean后置处理器将对所有的Bean生效。
测试
package com.lay.ioc.config;
public class IoCTest {
private static Logger log = LoggerFactory.getLogger(IocApplication.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
Person person=ctx.getBean(Programmer.class);
//关闭IoC容器
ctx.close();
}
}
观察日志
BeanPostProcess调用postProcessBeforeInitialization()方法,参数【BasketShoes】 【basketShoes】
BeanPostProcess调用postProcessAfterInitialization()方法,参数【BasketShoes】 【basketShoes】
18:08:31.354 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'basketShoes'
18:08:31.354 [main] DEBUG org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - Autowiring by type from bean name 'programmer' to bean named 'basketShoes'
延迟依赖注入
【Programmer】调用BeanNameAware的setBeanName()方法
【Programmer】调用BeanFactoryAware的setBeanFactory()方法
【Programmer】调用ApplicationContextAware的setApplicationContext()方法
BeanPostProcess调用postProcessBeforeInitialization()方法,参数【Programmer】 【programmer】
18:08:31.354 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Invoking init method on bean 'programmer': public void com.lay.ioc.pojo.Programmer.init()
【Programmer】调用注解@PostConstruct定义的自定义初始化方法
18:08:31.354 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'programmer'
【Programmer】调用InitializingBean的afterPropertiesSet()方法
BeanPostProcess调用postProcessAfterInitialization()方法,参数【Programmer】 【programmer】
18:08:31.354 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Finished creating instance of bean 'programmer'
18:08:31.355 [main] INFO org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@490d6c15: startup date [Mon Oct 22 18:08:30 CST 2018]; root of context hierarchy
18:08:31.355 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
18:08:31.356 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@57855c9a: defining beans org.springframework.boot.autoconfigure.info.ProjectInfoProperties,org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,restTemplateBuilder]; root of factory hierarchy
18:08:31.356 [main] DEBUG org.springframework.context.annotation.CommonAnnotationBeanPostProcessor - Invoking destroy method on bean 'programmer': public void com.lay.ioc.pojo.Programmer.destroy1()
【Programmer】调用 注解@PreDestroy定义的自定义销毁方法
18:08:31.356 [main] DEBUG org.springframework.beans.factory.support.DisposableBeanAdapter - Invoking destroy() on bean with name 'programmer'
【Programmer】调用DisposableBean的destroy()方法
从日志中可以看出,对于Bean后置处理器(BeanPostProcessor)而言,它对所有的Bean都起作用。而其他的接口则是对于单个Bean起作用。有时候Bean的定义可能使用的是第三方的类,此时可以使用注解@Bean来配置自定义初始化和销毁方法,如下
@Bean(initMethod="init",destroyMethod="destroy")
下一篇 Spring Boot IoC(六)使用properties配置文件