本篇内容介绍了“Spring Bean的生命周期怎么配置”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
五种作用域中,request、session和global session三种作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。
当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:
<bean id="account" class="com.spring.master.Account" scope="prototype"/>
//或者
<bean id="account" class="com.spring.master.Account" singleton="false"/>
当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="loginAction" class=cn.spring.master.LoginAction" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="userPreferences" class="com.spring.master.UserPreferences" scope="session"/>
针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。
当一个bean的作用域为Global Session,表示在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:
<bean id="user" class="com.spring.master.Preferences "scope="globalSession"/>
global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
在传统的 Java 应用中,bean 的生命周期很简单,使用 Java 关键字 new 进行Bean 的实例化,然后该 Bean 就能够使用了。一旦 bean 不再被使用,则由 Java 自动进行垃圾回收。相比之下,Spring 管理 Bean 的生命周期就复杂多了,正确理解 Bean 的生命周期非常重要,因为 Spring 对 Bean 的管理可扩展性非常强,下面展示了一个 Bean 的构造过程。
Spring对bean进行实例化;
Spring将值和bean的引用注入到bean对应的属性中;
如果bean实现了BeanNameAware接口,Spring将bean的ID传递给 setBean-Name()方法;
如果bean实现了BeanFactoryAware接口,Spring将调 用setBeanFactory()方法,将BeanFactory容器实例传入;
如果bean实现了ApplicationContextAware接口,Spring将调 用setApplicationContext()方法,将bean所在的应用上下文的 引用传入进来;
如果bean实现了BeanPostProcessor接口,Spring将调用它们 的post-ProcessBeforeInitialization()方法;
如果bean实现了InitializingBean接口,Spring将调用它们的 after-PropertiesSet()方法。类似地,如果bean使用init- method声明了初始化方法,该方法也会被调用;
如果bean实现了BeanPostProcessor接口,Spring将调用它们 的post-ProcessAfterInitialization()方法;
此时,bean已经准备就绪,可以被应用程序使用了,它们将一直 驻留在应用上下文中,直到该应用上下文被销毁;
如果bean实现了DisposableBean接口,Spring将调用它的 destroy()接口方法。同样,如果bean使用destroy-method声明 了销毁方法,该方法也会被调用。
package com.spring.master.spring.bean.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @author Huan Lee
* @version 1.0
* @date 2020-09-23 11:02
* @describtion 业精于勤,荒于嬉;行成于思,毁于随。
*/
public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String name;
public Person(){
System.out.println("1、开始实例化 person ");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("2、设置 name 属性");
}
@Override
public void setBeanName(String beanId) {
System.out.println("3、Person 实现了 BeanNameAware 接口,Spring 将 Person 的 "
+ "ID=" + beanId + "传递给 setBeanName 方法");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4、Person 实现了 BeanFactoryAware 接口,Spring 调"
+ "用 setBeanFactory()方法,将 BeanFactory 容器实例传入");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("5、Person 实现了 ApplicationContextAware 接口,Spring 调"
+ "用 setApplicationContext()方法,将 person 所在的应用上下文的"
+ "引用传入进来");
}
/**
* 自定义初始化方法
*/
@PostConstruct
public void springPostConstruct(){
System.out.println("7、@PostConstruct 调用自定义的初始化方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("8、Person 实现了 InitializingBean 接口,Spring 调用它的"
+ "afterPropertiesSet()方法。类似地,如果 person 使用 init-"
+ "method 声明了初始化方法,该方法也会被调用");
}
/**
* xml 中声明的 init-method 方法
*/
public void initMethod(){
System.out.println("9、xml 中声明的 init-method 方法");
}
/**
* 自定义销毁方法
*/
@PreDestroy
public void springPreDestory(){
System.out.println("12、@PreDestory 调用自定义销毁方法");
}
@Override
public void destroy() throws Exception {
System.out.println("13、Person 实现了 DisposableBean 接口,Spring 调用它的"
+ "destroy() 接口方法。同样,如果 person 使用 destroy-method 声明"
+ "了销毁方法,该方法也会被调用");
}
/**
* xml 中声明的 destroy-method 方法
*/
public void destroyMethod(){
System.out.println("14、xml 中声明的 destroy-method 方法");
System.out.println("end---------------destroy-----------------");
}
@Override
protected void finalize() throws Throwable {
System.out.println("finalize 方法");
}
}
package com.spring.master.spring.bean.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author Huan Lee
* @version 1.0
* @date 2020-09-23 11:31
* @describtion 后置处理器
*/
public class PersonBeanPostProcessor implements BeanPostProcessor {
// 容器加载的时候会加载一些其他的 bean,会调用初始化前和初始化后方法
// 这次只关注 Person 的生命周期
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Person){
System.out.println("6、初始化 Person 之前执行的方法");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof Person){
System.out.println("10、初始化 Person 完成之后执行的方法");
}
return bean;
}
}
后置处理器是什么?
一个类,实现了接口 BeanPostProcessor 定义的两个方法,这两个方法分别是:postProcessBeforeInitialization 和 postProcessAfterInitialization,顾名思义,就是分别在 bean 的 init-method 前后进行分别执行这两个方法。多后置处理器的有序性的 bean 在使用的过程中可以经过多个后置预处理的处理,但是,一般情况下,多个实现后置处理器接口的类是有先后顺序的,为了让 IOC 明白后置处理器之间的先后顺序,类还要实现 Ordered 接口,通过接口里的 order 属性来控制后处理器的先后顺序,默认为 0,为最高优先级。同一个容器中的后置处理器是通用的一个 context 中的后置处理器实现类不是针对某一个的 bean,这个 context 中的所有 bean 的产生过程都回去调用这个后置处理器,为了有针对性,可以通过 bean 的 id 来执行特异话的操作。
resource 文件夹下新建一个 bean_lifecycle.xml 文件注入相关 bean ,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描bean -->
<context:component-scan base-package="com.spring.master.spring.bean.lifecycle"/>
<!-- 实现了用户自定义初始化和销毁方法 -->
<bean id="person" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod">
<!-- 注入bean 属性名称 -->
<property name="name" value="HLee" />
</bean>
<!--引入自定义的BeanPostProcessor-->
<bean class="com.spring.master.spring.bean.lifecycle.PersonBeanPostProcessor"/>
</beans>
package com.spring.master;
import com.spring.master.spring.bean.lifecycle.Person;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SpringBootApplication
public class SpringMasterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringMasterApplication.class, args);
// 为面试而准备的Bean生命周期加载过程
ApplicationContext context = new ClassPathXmlApplicationContext("bean_lifecycle.xml");
Person person = (Person)context.getBean("person");
// 使用属性
System.out.println("11、实例化完成使用属性:Person name = " + person.getName());
// 关闭容器
((ClassPathXmlApplicationContext) context).close();
}
}
输出结果:
1、开始实例化 person
2、设置 name 属性
3、Person 实现了 BeanNameAware 接口,Spring 将 Person 的 ID=person传递给 setBeanName 方法
4、Person 实现了 BeanFactoryAware 接口,Spring 调用 setBeanFactory()方法,将 BeanFactory 容器实例传入
5、Person 实现了 ApplicationContextAware 接口,Spring 调用 setApplicationContext()方法,将 person 所在的应用上下文的引用传入进来
6、初始化 Person 之前执行的方法
7、@PostConstruct 调用自定义的初始化方法
8、Person 实现了 InitializingBean 接口,Spring 调用它的afterPropertiesSet()方法。类似地,如果 person 使用 init-method 声明了初始化方法,该方法也会被调用
9、xml 中声明的 init-method 方法
10、初始化 Person 完成之后执行的方法
11、实例化完成使用属性:Person name = HLee
12、@PreDestory 调用自定义销毁方法
13、Person 实现了 DisposableBean 接口,Spring 调用它的destroy() 接口方法。同样,如果 person 使用 destroy-method 声明了销毁方法,该方法也会被调用
14、xml 中声明的 destroy-method 方法
end---------------destroy-----------------
finalize 方法
当 person 默认是单例模式时,bean 的生命周期与容器的生命周期一样,容器初始化,bean 也初始化。容器销毁,bean 也被销毁。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描bean -->
<context:component-scan base-package="com.spring.master.spring.bean.lifecycle"/>
<!-- 实现了用户自定义初始化和销毁方法 -->
<bean id="person" scope="prototype" class="com.spring.master.spring.bean.lifecycle.Person" init-method="initMethod" destroy-method="destroyMethod">
<!-- 注入bean 属性名称 -->
<property name="name" value="HLee" />
</bean>
<!--引入自定义的BeanPostProcessor-->
<bean class="com.spring.master.spring.bean.lifecycle.PersonBeanPostProcessor"/>
</beans>
输出:
1、开始实例化 person
2、设置 name 属性
3、Person 实现了 BeanNameAware 接口,Spring 将 Person 的 ID=person传递给 setBeanName 方法
4、Person 实现了 BeanFactoryAware 接口,Spring 调用 setBeanFactory()方法,将 BeanFactory 容器实例传入
5、Person 实现了 ApplicationContextAware 接口,Spring 调用 setApplicationContext()方法,将 person 所在的应用上下文的引用传入进来
6、初始化 Person 之前执行的方法
7、@PostConstruct 调用自定义的初始化方法
8、Person 实现了 InitializingBean 接口,Spring 调用它的afterPropertiesSet()方法。类似地,如果 person 使用 init-method 声明了初始化方法,该方法也会被调用
9、xml 中声明的 init-method 方法
10、初始化 Person 完成之后执行的方法
11、实例化完成使用属性:Person name = HLee
finalize 方法
此时,容器关闭,person 对象并没有销毁。原因在于,单实例模式下,bean 的生命周期由容器管理,容器生,bean 生;容器死,bean 死。而在多实例模式下,Spring 就管不了那么多了,bean 的生命周期,交由客户端也就是程序员或者 JVM 来进行管理。
备注:修改对应的xml即可
“Spring Bean的生命周期怎么配置”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/3727895/blog/4638459