千家信息网

Spring Bean的生命周期怎么配置

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,本篇内容介绍了"Spring Bean的生命周期怎么配置"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成
千家信息网最后更新 2025年01月24日Spring Bean的生命周期怎么配置

本篇内容介绍了"Spring Bean的生命周期怎么配置"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

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的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

  • 当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

针对某个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定义:

global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。

Spring 生命周期

Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

在传统的 Java 应用中,bean 的生命周期很简单,使用 Java 关键字 new 进行Bean 的实例化,然后该 Bean 就能够使用了。一旦 bean 不再被使用,则由 Java 自动进行垃圾回收。相比之下,Spring 管理 Bean 的生命周期就复杂多了,正确理解 Bean 的生命周期非常重要,因为 Spring 对 Bean 的管理可扩展性非常强,下面展示了一个 Bean 的构造过程。

  1. Spring对bean进行实例化;

  2. Spring将值和bean的引用注入到bean对应的属性中;

  3. 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给 setBean-Name()方法;

  4. 如果bean实现了BeanFactoryAware接口,Spring将调 用setBeanFactory()方法,将BeanFactory容器实例传入;

  5. 如果bean实现了ApplicationContextAware接口,Spring将调 用setApplicationContext()方法,将bean所在的应用上下文的 引用传入进来;

  6. 如果bean实现了BeanPostProcessor接口,Spring将调用它们 的post-ProcessBeforeInitialization()方法;

  7. 如果bean实现了InitializingBean接口,Spring将调用它们的 after-PropertiesSet()方法。类似地,如果bean使用init- method声明了初始化方法,该方法也会被调用;

  8. 如果bean实现了BeanPostProcessor接口,Spring将调用它们 的post-ProcessAfterInitialization()方法;

  9. 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直 驻留在应用上下文中,直到该应用上下文被销毁;

  10. 如果bean实现了DisposableBean接口,Spring将调用它的 destroy()接口方法。同样,如果bean使用destroy-method声明 了销毁方法,该方法也会被调用。

验证 Spring Bean 周期

1. singleton

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 ,代码如下:                                            
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;@SpringBootApplicationpublic 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 = HLee12、@PreDestory 调用自定义销毁方法13、Person 实现了 DisposableBean 接口,Spring 调用它的destroy() 接口方法。同样,如果 person 使用 destroy-method 声明了销毁方法,该方法也会被调用14、xml 中声明的 destroy-method 方法end---------------destroy-----------------finalize 方法当 person 默认是单例模式时,bean 的生命周期与容器的生命周期一样,容器初始化,bean 也初始化。容器销毁,bean 也被销毁。

2. protoType

                                            输出: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 = HLeefinalize 方法

此时,容器关闭,person 对象并没有销毁。原因在于,单实例模式下,bean 的生命周期由容器管理,容器生,bean 生;容器死,bean 死。而在多实例模式下,Spring 就管不了那么多了,bean 的生命周期,交由客户端也就是程序员或者 JVM 来进行管理。

备注:修改对应的xml即可

"Spring Bean的生命周期怎么配置"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

方法 实例 接口 作用 容器 周期 生命 应用 处理 处理器 属性 对象 有效 上下 上下文 状态 管理 时候 过程 所在 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 大话2天粹英华服务器 企业网络技术开发好处 做软件开发的欧美企业 静安区网络技术开发服务要求 工业互联网服务器概念股 澳门六开彩金牛版免费资料服务器 邯郸进销存软件开发团队 预防网络安全的责任在政府 网络安全法 教育 软件开发和使用所涉及的判断题 数据库 美国国会 电脑网络技术路线图简笔画 抢先服服务器爆满 数据库如何用excel建表 河南网络时钟监控网管服务器 遥感应用软件开发是干啥的 数据库如何追加约束条件 软件开发选择笔记本 宽带没网络dns服务器 河北项目软件开发哪家好 sql中增加一条数据库 私有云服务器是物理服务器吗 网络技术在电子商务中运用 国内网络安全检测工具 服务器链接异常是什么情况 学习成绩不好可以学软件开发吗 如何做好税收网络安全工作 技术数据库 无法用流量打开服务器 长宁区项目软件开发经验丰富
0