Bean生命周期
针对部分同学说的不理解Bean生命周期面试题里面的长篇大论的描述,今天带大家把每个步骤都过一遍,并教会大家正确的理解其问题,以及组织自己的语言描述它。
目前网络上流行的bean生命周期描述大致为以下流程
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
- 如果Bean的方法上加了@PostConstruct注解,也会执行该初始化代码
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果当前bean的 @Bean 注解的属性里面有initMethod属性指向的方法,则也会执行该方法
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果bean实现了
@PreDestroy
注解的方法 或者 DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
乍一看,太多了,根本背不过来。还有就是为什么是这些流程呢?
生命周期的概念其实在Spring官网上就已经描述过了
大致分为5个部分
Initialization Callbacks(初始化回调)
意思是实现 InitializingBean 接口,它有个方法
void afterPropertiesSet() throws Exception;
但实际上Spring并不推荐这种方式,更推荐用@PostConstruct注释,这样可以和Spring容器进行解耦操作。
另外还可以指定POJO初始化方法。
如下代码所示
一、引导类
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
MyBean bean = context.getBean(MyBean.class);
System.out.println(bean);
}
}
二、配置类
@Configuration
public class MyBeanConfig {
@Bean(initMethod = "init")
public MyBean myBean() {
return new MyBean();
}
}
三、普通bean
public class MyBean {
public MyBean() {
System.out.println("构造方法");
}
@PostConstruct
public void postConstruct(){
System.out.println("PostConstruct");
}
public void init() {
System.out.println("initMethod");
}
}
那这段代码之后后的结果如下
Destruction Callbacks(销毁回调)
实现DisposableBean接口可以在上下文容器被销毁时触发bean的销毁方法的回调。
public class MyBean implements DisposableBean {
public MyBean() {
System.out.println("构造方法");
}
@PreDestroy
public void preDestroy() {
System.out.println("spring推荐的销毁方法");
}
//实现接口的销毁方法
@Override
public void destroy() throws Exception {
System.out.println("destroy()");
}
//自定义销毁方法
public void myClose() {
System.out.println("myClose()");
}
}
同样的Spring也不推荐这种操作,Spring建议你使用@PreDestroy
注解,同样是为了和Spring解藕。
当然你也可以自己定义销毁方法 如
@Configuration
public class MyBeanConfig {
//自己定义销毁方法
@Bean(destroyMethod = "myClose")
public MyBean myBean() {
return new MyBean();
}
}
还有一个接口其实也能做自动销毁,就是AutoCloseable。实现它其实有2个前提条件,官网并没有说明,这里讲一下,就是不能实现DisposableBean,以及不能自定义销毁方法也就是@Bean(destroyMethod = “myClose”)
这个在Spirng源码里才有所体现
@Nullable
private String inferDestroyMethodIfNecessary(Object bean, RootBeanDefinition beanDefinition) {
String destroyMethodName = beanDefinition.getDestroyMethodName();.
//这里清楚说明在自定义销毁方法没有设置
if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName) ||
(destroyMethodName == null && bean instanceof AutoCloseable)) {
// Only perform destroy method inference or Closeable detection
// in case of the bean not explicitly implementing DisposableBean
// 并且DisposableBean接口没有实现,才会执行close方法,或者shutdown方法
if (!(bean instanceof DisposableBean)) {
try {
return bean.getClass().getMethod(CLOSE_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex) {
try {
return bean.getClass().getMethod(SHUTDOWN_METHOD_NAME).getName();
}
catch (NoSuchMethodException ex2) {
// no candidate destroy method found
}
}
}
return null;
}
return (StringUtils.hasLength(destroyMethodName) ? destroyMethodName : null);
}
当然你所有方法都不实现,只定义close方法,或者只定义shutdown方法也行,优先执行close。这个在上面代码中也有所体现。
Default Initialization and Destroy Methods(默认初始化和销毁方法)
每个bean都定义生命周期的初始化和销毁太麻烦了,Spring在 设置好默认的方法,这样所有bean都可以用了,比较方便。
并且,如果子类重新覆盖则以子类为准
Combining Lifecycle Mechanisms(结合生命周期机制)
如果你配置了多个生命周期定义在同一个方法上,那这个方法只会执行一次,例如
@Configuration
public class MyBeanConfig {
@Bean(initMethod = "init")
public MyBean myBean() {
return new MyBean();
}
}
public class MyBean {
@PostConstruct
public void init() {
System.out.println("init()");
}
public MyBean() {
System.out.println("构造方法");
}
}
自定义初始化方法和PostConstruct注解都指向同一个方法时,只会调用一次Bean生命周期
public class MyBean {
@PostConstruct
public void myInit() {
System.out.println("myInit()");
}
public void init() {
System.out.println("init()");
}
public MyBean() {
System.out.println("构造方法");
}
}
分开后就可以分别执行。同样的道理也能放在@PreDestroy 和 自定义的销毁方法上
他们的执行顺序
public class MyBean implements InitializingBean , DisposableBean {
@PostConstruct
public void init() {
System.out.println("@PostConstruct spring推荐的初始化方法");
}
public MyBean() {
System.out.println("构造方法");
}
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy spring推荐的销毁方法");
}
//自定义销毁方法
public void myClose() {
System.out.println("myClose() 自定义销毁方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实现InitializingBean接口的afterPropertiesSet()");
}
private void myInit() {
System.out.println("myInit() 自定义初始化方法");
}
@Override
public void destroy() throws Exception {
System.out.println("实现DisposableBean接口的destroy()");
}
}
@Configuration
public class MyBeanConfig {
@Bean(initMethod = "myInit",destroyMethod = "myClose")
public MyBean myBean() {
return new MyBean();
}
}
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
MyBean bean = context.getBean(MyBean.class);
context.close();
}
}
初始化方法顺序
@PostConstruct
- 实现
InitializingBean
接口 - 自定义初始化方法
销毁方法顺序
@PreDestroy
- 实现
DisposableBean
接口 - 自定义销毁方法
Startup and Shutdown Callbacks (启动和停止的回调)
Lifecycle
有一个接口org.springframework.context.Lifecycle
,我们用bean去实现该接口,会有3个方法
public class MyBean implements Lifecycle {
private boolean running = false;
@Override
public void start() {
running = true;
System.out.println("start()");
}
@Override
public void stop() {
running = false;
System.out.println("stop()");
}
@Override
public boolean isRunning() {
System.out.println("isRunning()==" + running);
return running;
}
}
在我们调用上下文的start和stop方法时,会先执行isRunning() 。
如果isRunning() 返回false 则 执行 bean的start()
如果isRunning() 返回true 则 执行 bean的stop()
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
context.start();
context.stop();
}
}
执行结果
Spring同时也提醒你这个接口的开始方法和关闭方法跟Spring上下文的刷新和销毁并无直接关联,需要上下文手动调用start() 和 stop(),并要配合isRunning的结果才能执行。
LifecycleProcessor
它是Lifecycle的子类实现,多了2个方法,而且这个使用方法比较特别,需要将bean的name定义成lifecycleProcessor,如下图
@Configuration
public class MyBeanConfig {
@Bean
public MyBean lifecycleProcessor() {
return new MyBean();
}
}
public class MyBean implements LifecycleProcessor {
private boolean running = false;
@Override
public void start() {
running = true;
System.out.println("start()");
}
@Override
public void stop() {
running = false;
System.out.println("stop()");
}
@Override
public boolean isRunning() {
System.out.println("isRunning()==" + running);
return running;
}
@Override
public void onRefresh() {
System.out.println("onRefresh");
}
@Override
public void onClose() {
System.out.println("onClose");
}
}
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContet context = new AnnotationConfigApplicationContet(MyBeanConfig.class);
context.start();
context.stop();
context.close();
}
}
运行结果如下
这会儿就不跟isRunning的结果有关系了,或者说根本没有调用isRunning。
SmartLifecycle
同样也是Lifecycle的子类,同样也多了2个方法,只不过有默认的实现。
public class MyBean implements SmartLifecycle {
private boolean running = false;
@Override
public void start() {
running = true;
System.out.println("MyBean start()");
}
@Override
public void stop() {
running = false;
System.out.println("MyBean stop()");
}
@Override
public boolean isRunning() {
System.out.println("MyBean isRunning()==" + running);
return running;
}
// 如果返回true则不需要调用上下文的start()同样也可以开启bean的start()
@Override
public boolean isAutoStartup() {
return true;
}
// 返回值越小最越早启动,越晚销毁,反之则越晚启动,越早销毁
@Override
public int getPhase() {
return 0;
}
}
public class MyBean2 implements SmartLifecycle {
private boolean running = false;
@Override
public void start() {
running = true;
System.out.println("MyBean2 start()");
}
@Override
public void stop() {
running = false;
System.out.println("MyBean2 stop()");
}
@Override
public boolean isRunning() {
System.out.println("MyBean2 isRunning()==" + running);
return running;
}
// 如果返回true则不需要调用上下文的start()同样也可以开启bean的start()
@Override
public boolean isAutoStartup() {
return true;
}
// 返回值越小最越早启动,越晚销毁,反之则越晚启动,越早销毁
@Override
public int getPhase() {
return 1;
}
}
@Configuration
public class MyBeanConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
public MyBean2 myBean2() {
return new MyBean2();
}
}
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
context.close();
}
}
执行结果如下
Shutting Down the Spring IoC Container Gracefully in Non-Web Applications (非web环境如何优雅的关闭IOC容器)
public class MyBean {
public void close() {
System.out.println("没有调用上下文的close,但由于注册的关闭的勾子,当应用关闭时会自动调用");
}
}
@Configuration
public class MyBeanConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyBeanConfig.class);
context.registerShutdownHook();
}
}
被遗忘的接口
以上就是所有Spring官网对于Bean的生命周期描述。但是这好像和我们之前背的生命周期有很大出入。如 BeanNameAware
接口、 BeanFactoryAware
接口 、ApplicationContextAware
接口,还有 BeanPostProcessor
接口 。首先这些接口其实并不在官网的生命周期回调接口篇章,只不过它们确实能在生命周期过程中影响Bean。
这些Aware接口就不用一个个探究了,因为太多了,大致都是实现接口后IOC会调用其set方法将我们需要的属性或bean进行注入。
这里我唯一想说的是这个BeanPostProcessor,基本上IOC的bean管理都依赖其子类的实现,离开它基本上IOC就玩不转了。
public class MyBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet()");
}
}
@Configuration
public class MyBeanConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName);
return bean;
}
}
public class SpringBeanApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
context.register(MyBeanConfig.class);
context.refresh();
}
}
执行结果如下
BeanPostProcessor会得到IOC容器里的所有Bean,并且你可以修改Bean,我们的Aware接口都是通过这个实现的。并且他的执行时机是在 执行 bean的afterPropertiesSet()方法前后。
至此,所有的方法都跟大家过了一遍。我们在日后的面试过程中,描述思路应该以Spirng官网的描述为准,说清楚有哪些生命周期,并且说清楚Aware接口和BeanPostProcessor并不应该属于生命周期包含的接口,但其作用和执行步骤在那一段可以描述清楚。