Bean的生命周期
ioc容器中bean的生命周期分为四个部分:
- Bean的定义
- Bean的初始化
- Bean的生存期
- Bean销毁
-
bean的定义过程
容器启动时,spring通过我们的配置扫描带有@Component、@Service等注解的类并进行解析,解析的过程可以说是读取了我们对Bean(类)的描述,生成了Bean(类)的定义,并将Bean(类)的定义保存起来。然后将该定义发布到ioc容器中,但此时容器中并没有生成Bean的实例。
bean定义的过程可以看作是扫描并发布Bean的过程。 -
bean的初始化
Bean的定义完成后,在默认的情况下ioc容器会进行初始化操作生成Bean的实例并完成依赖注入。
若是想要在我们取出Bean的时候再让ioc容器对其进行初始化,则可以使用@ComponentScan中的配置项lazyInit实现懒加载。如下:
@ComponentScan(basePackages="com.example.demo.*",lazyInit = false)
public class MyConfig {
}
lazyInit属性默认为false,即不进行延迟加载。若配置为true,则该Bean在我们使用@Autowired进行注入时才进行初始化。
- @PostConstruct注解
该注解是由java提供的,java中的说明: @PostConstruct用来修饰一个非静态的void方法,该方法在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Servlet的inti()方法。被@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行。
在spring中,被@PostConstruct修饰的方法在@Autowired之后立即执行,可以用来实现一些自定义的初始化。什么意思呢,看如下的代码:
public class MyTest {
private String m;
@Autowired
private MyTest1 mytest1;
public MyTest() {
}
@PostConstruct
public void init() {
System.out.println("mytest1自定义初始化操作");
}
}
在ioc容器对MyTest进行初始化时,首先会执行MyTest的构造方法,然后变量m会被赋予初值。而mytest1依赖于依赖注入,无法在构造方法中进行初始化,而我们又需要完成某些自定义的初始化操作,则可以使用@PostConstruct注解方法来进行初始化。
- 实现InitializingBean接口
自定义初始化还可以通过重写InitializingBean接口的afterPropertiesSet()方法来进实现。注意:若存在@PostConstruct修饰的方法,则afterPropertiesSet()方法在其之后执行。
- bean的生存期
bean的生存期即bean在程序运行时的流转。 - bean的销毁
- @PreDestroy注解
用@PreDestroy标注的方法可以在bean销毁之前进行自定义的相关操作 - 实现DisposableBean接口,重写destory方法
网上大部分资料中显示:在servlet生命周期中,@PreDestroy注解标注的方法会在destory()方法之后,servlet对象彻底销毁前执行。(servlet中的执行顺序我还没有进行测试)
我们先来看一下上述两种方法在bean生命周期中的执行顺序。
@Component
public class MyTest implements DisposableBean{
@Override
public void destroy() throws Exception {
System.out.println("执行destory方法");
}
@PreDestroy
public void preDestoryTest() {
System.out.println("preDestory方法执行");
}
}
修改MyTest类,启动应用并关闭应用,控制台打印信息如下:
2019-02-14 16:27:07.379 DEBUG 14356 --- [on(2)-127.0.0.1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2019-02-14 16:27:07.379 DEBUG 14356 --- [on(2)-127.0.0.1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans
2019-02-14 16:27:07.380 INFO 14356 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
preDestory方法执行
执行destory方法
2019-02-14 16:27:07.456 INFO 14356 --- [on(2)-127.0.0.1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-02-14 16:27:07.461 INFO 14356 --- [on(2)-127.0.0.1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-02-14 16:27:07.477 INFO 14356 --- [on(2)-127.0.0.1]
可以看出@PreDestroy注解修饰的方法会在destory方法之前执行。
- 使用@Bean (initMethod = ” init ”, destroyMethod = ” destroy” )来自定义bean初始化和销毁时的一些操作。首先需要一个提供自定义方法的类:
package com.example.demo.test;
public class InitAndDestory {
public void init() {
System.out.println("自定义init");
}
public void destory() {
System.out.println("自定义destory");
}
}
接着继续修改MyTest类:
package com.example.demo.test;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class MyTest implements DisposableBean{
@Bean(initMethod = "init", destroyMethod = "destory")
public InitAndDestory iAd() {
return new InitAndDestory();
}
@PostConstruct
public void postConstructTest() {
System.out.println("postConstruct方法执行");
}
@PreDestroy
public void preDestoryTest() {
System.out.println("preDestory方法执行");
}
@Override
public void destroy() throws Exception {
System.out.println("这是实现DisposableBean接口的destory方法");
}
}
启动然后关闭应用,结果如下:
2019-02-15 17:06:38.337 INFO 20508 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2019-02-15 17:06:38.345 INFO 20508 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
自定义destory
preDestory方法执行
这是实现DisposableBean接口的destory方法
2019-02-15 17:06:38.361 INFO 20508 --- [on(2)-127.0.0.1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-02-15 17:06:38.366 INFO 20508 --- [on(2)-127.0.0.1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-02-15 17:06:38.377 INFO 20508 --- [on(2)-127.0.0.1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
继续修改看结果:
@Component
public class MyTest{
@Bean(initMethod = "init", destroyMethod = "destory")
public InitAndDestory iAd() {
return new InitAndDestory();
}
@PostConstruct
public void postConstructTest() {
System.out.println("postConstruct方法执行");
}
@PreDestroy
public void preDestoryTest() {
System.out.println("preDestory方法执行");
}
}
2019-02-15 17:36:58.614 INFO 30372 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2019-02-15 17:36:58.622 INFO 30372 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
自定义destory
preDestory方法执行
2019-02-15 17:36:58.640 INFO 30372 --- [on(2)-127.0.0.1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-02-15 17:36:58.643 INFO 30372 --- [on(2)-127.0.0.1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-02-15 17:36:58.655 INFO 30372
再次修改看输出结果:
@Component
public class MyTest implements DisposableBean,InitializingBean{
@Bean(initMethod = "init", destroyMethod = "destory")
public InitAndDestory iAd() {
return new InitAndDestory();
}
@PostConstruct
public void postConstructTest() {
System.out.println("postConstruct方法执行");
}
// @PreDestroy
// public void preDestoryTest() {
// System.out.println("preDestory方法执行");
// }
@Override
public void destroy() throws Exception {
System.out.println("这是实现DisposableBean接口的destory方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("这是实现InitializingBean接口中的方法");
}
}
2019-02-15 17:29:56.961 INFO 45040 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
postConstruct方法执行
这是实现InitializingBean接口中的方法
自定义init
2019-02-15 17:30:57.474 INFO 45040 --- [on(2)-127.0.0.1] inMXBeanRegistrar$SpringApplicationAdmin : Application shutdown requested.
2019-02-15 17:30:57.484 INFO 45040 --- [on(2)-127.0.0.1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
自定义destory
这是实现DisposableBean接口的destory方法
2019-02-15 17:30:57.498 INFO 45040 --- [on(2)-127.0.0.1] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-02-15 17:30:57.501 INFO 45040 --- [on(2)-127.0.0.1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-02-15 17:30:57.510 IN
经过上述测试,bean初始化的顺序如下:
- bean在实例化之后,初始化之前都会执行postProcessBeforeInitialization方法,在初始化完成后执行postProcessAfterInitialization方法。
- 若存在@PostConstruct修饰的方法,则执行该方法。
- 若实现了InitializingBean接口,则执行其afterPropertiesSet方法。
- 若存在我们自定义的init方法,则执行自定义方法。
bean在销毁时各个方法的顺序与网上资料中存在出入:自定义的destory方法始终在@PreDestroy修饰的销毁方法之前执行,实现DisposableBean接口重写的方法始终在最后执行(该结果与书中描述相符)。
注意:bean在初始化和销毁时,我们可以通过上述方法进行相应的自定义操作,但并不是执行了我们自定义的这些方法而完成了初始化和销毁。bean的初始化和销毁是一个过程,在过程中会相应的执行我们重写或自定义的方法。且上述测试是默认bean为单例的情况,若不是单例的bean,则初始化时仍会自动执行相关方法,但销毁时不会自动执行destory相关方法,需要由我们自己去调用。
Bean的作用域
作用域类型 | 使用范围 | 作用域描述 |
---|---|---|
singleton | 所有spring应用 | ioc容器的默认值,只存在一个bean实例 |
prototype | 所有spring应用 | 每从容器中取出一次bean,都是一个新的实例 |
session | 所有spring web应用 | http会话 |
application | 所有spring web应用 | web工程生命周期 |
request | 所有spring web应用 | web的单次请求 |
globalSession | 所有spring web应用 | 在一个全局的httpSession中,一个bean对应一个实例 |
再复习一下会话(http)和请求(request)
- 请求(request)
http协议是无状态的,也就是说,发送一次请求得到响应之后,再次发送请求,服务器已经不知道你上一次请求所发送的任何信息。 - 会话(session)
session会话会占用服务器的一段内存空间保存多个有联系request请求之间需要保存的共享变量,大部分session的实现对同一客户的 相同 浏览器的 一段时间 (即session超时时间)内的请求作状态共享和保持,不同浏览器之间的session不共享。