本篇内容介绍了“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的生命周期怎么配置”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。