Spring Bean生命周期

举报
CoderX 发表于 2022/04/06 14:00:34 2022/04/06
【摘要】 传统Bean生命周期传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。 Spring Bean生命周期 Spring Bean的生命周期Spring中Bean的生命周期大致分为5个阶段:Bean的实例化Bean属性赋值Bean的初始化B...

传统Bean生命周期

传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。

Spring Bean生命周期

Spring Bean的生命周期

Spring中Bean的生命周期大致分为5个阶段:

  1. Bean的实例化
  2. Bean属性赋值
  3. Bean的初始化
  4. Bean的使用
  5. Bean的销毁

Bean的管理

Spring 根据 Bean 的作用域来选择 Bean 的管理方式:

  • 对于 singleton 作用域的 Bean 来说,Spring IoC 容器能够精确地控制 Bean 何时被创建、何时初始化完成以及何时被销毁;
  • 对于 prototype 作用域的 Bean 来说,Spring IoC 容器只负责创建,然后就将 Bean 的实例交给客户端代码管理,Spring IoC 容器将不再跟踪其生命周期。

Spring生命周期流程

Spring Bean 的完整生命周期从创建 Spring IoC 容器开始,直到最终 Spring IoC 容器销毁 Bean 为止,其具体流程如下图所示。

Spring 生命周期流程

自定义Bean的生命周期

​ 在 Spring Bean 生命周期的某个特定时刻,指定一些生命周期回调方法完成一些自定义的操作,对 Bean 的生命周期进行管理。

  1. 回调方法:
    • 初始化回调方法:在 Spring Bean 被初始化后调用,执行一些自定义的回调操作。
    • 销毁回调方法:在 Spring Bean 被销毁前调用,执行一些自定义的回调操作。
  2. 自定义Bean的生命周期回调方法的方式:(按照优先级顺序)
    • 通过注解
    • 通过接口
    • 通过XML配置

1)通过接口实现

​ 可以在 Spring Bean 的 Java 类中,通过实现 InitializingBean(初始化Bean)和 DisposableBean(一次性Bean) 接口,指定 Bean 的生命周期回调方法。

​ 注:一般不建议通过这种方式指定生命周期回调方法,会导致代码的耦合性过高。

回调方式 接口 方法 说明
初始化回调 InitializingBean afterPropertiesSet() 指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
销毁回调 DisposableBean destroy() 指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

代码示例:

  1. Java类

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    /***
     * 使用接口,实现初始化回调 和销毁回调
     */
    public class LifeCycleBean implements InitializingBean, DisposableBean {
        private static final Log LOGGER= LogFactory.getLog(LifeCycleBean.class);
        private  String webName; //网站名称
        private String  url;  //网站地址
    
        public void setWebName(String webName) {
            this.webName = webName;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        @Override
        public String toString() {
            return "LifeCycleBean{" +
                    "webName='" + webName + '\'' +
                    ", url='" + url + '\'' +
                    '}';
        }
    
        /**
         * 初始化回调逻辑
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            LOGGER.info("调用接口:InitializeingBean,方法:afterPropertiesSet(),无参数");
        }
        /**
         * 销毁回调逻辑
         * @throws Exception
         */
        @Override
        public void destroy() throws Exception {
    
            LOGGER.info("调用接口:DisposableBean,方法:destroy,无参数");
        }
    
    }
    
    
  2. XML配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <!--通过接口自定义生命周期-->
        <bean id="lifeCycleBean" class="org.demo6.LifeCycleBean">
            <property name="webName" value="bdqn"/>
            <property name="url" value="com.bdqn.www"/>
        </bean>
    
    </beans>
    
  3. main方法

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
        private static final Log LOGGER = LogFactory.getLog(MainApp.class);
        public static void main(String[] args) {
            //获取 ClassPathXmlApplicationContext 容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo6beans.xml");
            LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
            LOGGER.info(lifeCycleBean);
            //手动销毁 Bean
            context.close();
        }
    }
    
    
  4. 运行结果

    329, 2022 3:49:40 下午 org.demo6.LifeCycleBean afterPropertiesSet
    信息: 调用接口:InitializeingBean,方法:afterPropertiesSet(),无参数
    329, 2022 3:49:40 下午 org.demo6.MainApp main
    信息: LifeCycleBean{webName='bdqn', url='com.bdqn.www'}
    329, 2022 3:49:40 下午 org.demo6.LifeCycleBean destroy
    信息: 调用接口:DisposableBean,方法:destroy,无参数
    

2)通过XML配置实现

在 Spring 的 XML 配置中,通过 <bean> 元素中的 init-method (初始化)和 destory-method(销毁)属性,指定 Bean 的生命周期回调方法。

XML 配置属性 描述
init-method 指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
destory-method 指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

代码示例:

  1. Java类

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    /**
     * 通过 XML 配置指定生命周期回调方法
     */
    public class XMLLifeCycleBean {
        private static final Log LOGGER = LogFactory.getLog(XMLLifeCycleBean.class);
        //网站名称
        private String webName;
        //网站地址
        private String url;
        public void setWebName(String webName) {
            this.webName = webName;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        @Override
        public String toString() {
            return "XMLLifeCycleBean{" +
                    "webName='" + webName + '\'' +
                    ", url='" + url + '\'' +
                    '}';
        }
        /**
         * 初始化回调方法
         */
        public void init() {
            LOGGER.info("在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法");
        }
        /**
         * 销毁回调方法
         */
        public void destroy() {
            LOGGER.info("在 XML 配置中通过 destroy-method 属性指定回调方法:destroy() 方法");
        }
    }
    
    
  2. XML配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <!--通过接口自定义生命周期-->
        <!--<bean id="lifeCycleBean" class="org.demo6.LifeCycleBean">
            <property name="webName" value="bdqn"/>
            <property name="url" value="com.bdqn.www"/>
        </bean>-->
    
        <!--通过XML配置指定生命周期回调方法-->
        <bean id="xmlLifeCycleBean" class="org.demo6.XMLLifeCycleBean" init-method="init" destroy-method="destroy">
            <property name="webName" value="bdqn"/>
            <property name="url" value="com.bdqn.www"/>
        </bean>
    
    </beans>
    
  3. Main方法

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * 三种方法实现自定义Spring bean生命周期
     */
    public class MainApp {
        private static final Log LOGGER = LogFactory.getLog(MainApp.class);
        public static void main(String[] args) {
            //获取 ClassPathXmlApplicationContext 容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo6beans.xml");
    
            /*
            * 接口方法
            */ 
            /*LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
            LOGGER.info(lifeCycleBean);
            //手动销毁 Bean
            context.close();*/
    
            /*
            *XML配置方法
            */
            XMLLifeCycleBean xmlbean=context.getBean("xmlLifeCycleBean",XMLLifeCycleBean.class);
            LOGGER.info(xmlbean);
    
            //手动销毁bean
            context.close();
        }
    }
    
    
    
  4. 运行结果

    329, 2022 4:12:28 下午 org.demo6.XMLLifeCycleBean init
    信息: 在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法
    329, 2022 4:12:28 下午 org.demo6.MainApp main
    信息: XMLLifeCycleBean{webName='bdqn', url='com.bdqn.www'}
    329, 2022 4:12:28 下午 org.demo6.XMLLifeCycleBean destroy
    信息: 在 XML 配置中通过 destroy-method 属性指定回调方法:destroy() 方法
    

3)通过注解实现

可以通过JSR-250的@PostConstruct和@PreDestroy注解,指定Bean的生命周期回调方法.

注解 描述
@PostConstruct 指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
@PreDestroy 指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

代码示例:

  1. java类

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * 注释生命周期类
     */
    public class AnnotationLifeCycleBean {
        private static final Log LOGGER = LogFactory.getLog(AnnotationLifeCycleBean.class);
        //网站名称
        private String webName;
        //网站地址
        private String url;
        public AnnotationLifeCycleBean(String webName, String url) {
            this.webName = webName;
            this.url = url;
        }
        @Override
        public String toString() {
            return "AnnotationLifeCycleBean{" +
                    "webName='" + webName + '\'' +
                    ", url='" + url + '\'' +
                    '}';
        }
        /**
         * 初始化回调方法
         */
        @PostConstruct
        public void init(){
            LOGGER.info("通过@PostConstrust注解,指定初始化方法,init()方法");
        }
    
        /**
         * 销毁回调方法
         */
        @PreDestroy
        public void destroy(){
            LOGGER.info("通过@PreDestroy注解,指定初始化方法,destroy()方法");
        }
    
    
    
    }
    
    
    
    
  2. 配置XML文件

    <?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-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
        <!--通过接口自定义生命周期-->
        <!--<bean id="lifeCycleBean" class="org.demo6.LifeCycleBean">
            <property name="webName" value="bdqn"/>
            <property name="url" value="com.bdqn.www"/>
        </bean>-->
    
        <!--通过XML配置指定生命周期回调方法-->
      <!--  <bean id="xmlLifeCycleBean" class="org.demo6.XMLLifeCycleBean" init-method="init" destroy-method="destroy">
            <property name="webName" value="bdqn"/>
            <property name="url" value="com.bdqn.www"/>
        </bean>
        -->
        <!--扫描组件-->
        <context:component-scan base-package="org.demo6"/>
    
        <!--通过注解指定Bean生命周期回调方法-->
       <bean id="annotationLifeCycleBean" class="org.demo6.AnnotationLifeCycleBean">
           <constructor-arg name="webName" value="bdqn"/>
           <constructor-arg name="url" value="com.bdqn.www"/>
       </bean>
    
    </beans>
    
  3. main方法

    package org.demo6;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * 三种方法实现自定义Spring bean生命周期
     */
    public class MainApp {
        private static final Log LOGGER = LogFactory.getLog(MainApp.class);
        public static void main(String[] args) {
            //获取 ClassPathXmlApplicationContext 容器
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo6beans.xml");
    
            /*
            * 接口方法
            */
    
            /*LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
            LOGGER.info(lifeCycleBean);
            */
    
            /*
            *XML配置方法
            */
            /*XMLLifeCycleBean xmlbean=context.getBean("xmlLifeCycleBean",XMLLifeCycleBean.class);
            LOGGER.info(xmlbean);*/
    
            /**
             * 注解配置方法
             */
            AnnotationLifeCycleBean annotationLifeCycleBean=context.getBean("annotationLifeCycleBean",AnnotationLifeCycleBean.class);
            LOGGER.info(annotationLifeCycleBean);
            /*System.out.println(annotationLifeCycleBean.toString());*/
    
    
            //手动销毁bean
            context.close();
        }
    }
    
    
  4. 运行结果

    16:24:31.394 [main] INFO org.demo6.AnnotationLifeCycleBean - 通过@PostConstrust注解,指定初始化方法,init()方法
    AnnotationLifeCycleBean{webName='bdqn', url='com.bdqn.www'}
    16:24:31.426 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Closing org.springframework.context.support.ClassPathXmlApplicationContext@4cf4d528, started on Wed Mar 30 16:24:30 CST 2022
    16:24:31.427 [main] INFO org.demo6.AnnotationLifeCycleBean - 通过@PreDestroy注解,指定初始化方法,destroy()方法
    
推荐

华为开发者空间发布

让每位开发者拥有一台云主机

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。