Spring Bean 生命周期
在 Spring 中,那些组成应用程序的主体及由 Spring IoC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IoC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
首先看下生命周期图:
bean 的五种作用域作
五种作用域中,request、session 和 global session 三种作用域仅在基于 web 的应用中使用(不必关心你所采用的是什么 web 应用框架),只能用在基于 web 的 Spring ApplicationContext 环境。
Singleton 作用域
- 当一个 bean 的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton 作用域是 Spring 中的缺省作用域。
要在 XML 中将 bean 定义成 singleton,可以这样配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
Prototype 作用域
- 当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取 bean 的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bea
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
request 作用域
- 当一个 bean 的作用域为 Request,表示在一次 HTTP 请求中,一个 bean 定义对应一个实例;即每个 HTTP 请求都会有各自的 bean 实例,它们依据某个 bean 定义创建而成。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
- 针对每次 HTTP 请求,Spring 容器会根据 loginAction bean 的定义创建一个全新的 LoginAction bean 实例,且该 loginAction bean 实例仅在当前 HTTP request 内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据 loginAction bean 定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request 作用域的 bean 实例将被销毁。
session 作用域
- 当一个 bean 的作用域为 Session,表示在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
global session 作用域
- 当一个 bean 的作用域为 Global Session,表示在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。典型情况下,仅在使用 portlet context 的时候有效。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="user" class="com.foo.Preferences "scope="globalSession"/>
- global session 作用域类似于标准的 HTTP Session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。
Bean 实例生命周期的执行过程如下:
- Spring 对 bean 进行实例化,默认 bean 是单例;
- Spring 对 bean 进行依赖注入;
- 如果 bean 实现了 BeanNameAware 接口,spring 将 bean 的 id 传给 setBeanName() 方法;
- 如果 bean 实现了 BeanFactoryAware 接口,spring 将调用 setBeanFactory 方法,将 BeanFactory 实例传进来;
- 如果 bean 实现了 ApplicationContextAware 接口,它的 setApplicationContext() 方法将被调用,将应用上下文的引用传入到 bean 中;
- 如果 bean 实现了 BeanPostProcessor 接口,它的 postProcessBeforeInitialization 方法将被调用;
- 如果 bean 实现了 InitializingBean 接口,spring 将调用它的 afterPropertiesSet 接口方法,类似的如果 bean 使用了 init-method 属性声明了初始化方法,该方法也会被调用;
- 如果 bean 实现了 BeanPostProcessor 接口,它的 postProcessAfterInitialization 接口方法将被调用;
- 此时 bean 已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 若 bean 实现了 DisposableBean 接口,spring 将调用它的 distroy() 接口方法。同样的,如果 bean 使用了 destroy-method 属性声明了销毁方法,则该方法被调用;
springBean 自定义初始化和销毁方法
springBoot 方式
public class SpringLifeCycle {
private final static Logger LOGGER = LoggerFactory.getLogger(LifeCycleConfig.class);
public void start(){
LOGGER.info("bean 初始化 start");
}
public void destroy(){
LOGGER.info("bean 销毁 destroy");
}
}
@Configuration
public class LifeCycleConfig {
@Bean(initMethod = "start", destroyMethod = "destroy")
public SpringLifeCycle create(){
SpringLifeCycle springLifeCycle = new SpringLifeCycle() ;
return springLifeCycle ;
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
@Test
public void contextLoads() {
System.out.println("dsadsasdasd");
SpringLifeCycle s=new SpringLifeCycle();
}
}
传统 xml 配置方式
<bean id="person1" destroy-method="myDestroy"
init-method="myInit" class="com.test.spring.life.Person">
<property name="name">
<value>jack</value>
</property>
</bean>
<!-- 配置自定义的后置处理器 -->
<bean id="postProcessor" class="com.pingan.spring.life.MyBeanPostProcessor" />
public class Person implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
public Person() {
System.out.println("PersonService 类构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("set 方法被调用");
}
//自定义的初始化函数
public void myInit() {
System.out.println("myInit 被调用");
}
//自定义的销毁方法
public void myDestroy() {
System.out.println("myDestroy 被调用");
}
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("destory 被调用");
}
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("afterPropertiesSet 被调用");
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
// TODO Auto-generated method stub
System.out.println("setApplicationContext 被调用");
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
// TODO Auto-generated method stub
System.out.println("setBeanFactory 被调用,beanFactory");
}
public void setBeanName(String beanName) {
// TODO Auto-generated method stub
System.out.println("setBeanName 被调用,beanName:" + beanName);
}
public String toString() {
return "name is :" + name;
}
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization 被调用");
return bean;
}
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization 被调用");
return bean;
}
}
测试类
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization 被调用");
return bean;
}
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization 被调用");
return bean;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("开始初始化容器");
ApplicationContext ac = new ClassPathXmlApplicationContext("com/test/spring/life/applicationContext.xml");
System.out.println("xml 加载完毕");
Person person1 = (Person) ac.getBean("person1");
System.out.println(person1);
System.out.println("关闭容器");
((ClassPathXmlApplicationContext)ac).close();
}
使用前面定义好的 Person 类和 MyBeanPostProcessor 类,以及 ApplicationContext.xml 文件,main 函数实现如下:
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("开始初始化容器");
ConfigurableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("com/pingan/spring/life/applicationContext.xml"));
System.out.println("xml 加载完毕");
//beanFactory 需要手动注册 beanPostProcessor 类的方法
bf.addBeanPostProcessor(new MyBeanPostProcessor());
Person person1 = (Person) bf.getBean("person1");
System.out.println(person1);
System.out.println("关闭容器");
bf.destroySingletons();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: eureka 注册中心访问权限
下一篇: AOP 面向切面编程
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论