容器中Bean的生命周期

    Spring可以管理singleton作用域Bean的生命周期,Spring可以精确的知道该Bean何时被创建、何时被初始化完成、容器何时准备销毁该Bean实列。

    对于prototype作用域的Bean,Spring容器仅负责创建,当容器创建了Bean实列之后,Bean实列完全交给客户端代码管理,容器不再跟踪其生命周期。

    对于singleton作用域的Bean,Spring容器知道Bean何时实列化结束、何时销毁。Spring可以管理Bean在实列化结束之后和销毁之前的行为。管理Bean的生命周期行为主要有如下两个时机:

    一、注入依赖关系后

    Spring提供两种方式在Bean注入依赖关系后执行特定行为;

 第一:在xml中配置<bean>时,为其配置init-method属性,该属性指定Bean全部依赖关系设置结束后,自动执行该属性指定的方法;

第二:让Bean类实现InitalizingBean接口,该接口提供public void afterPropertiesSet() throws Exception方法。

    <!--使用init-method指定Bean注入后执行方法-->
	<bean id="init" class="com.custle.spring.Init" init-method="init"/>
package com.custle.spring;

import org.springframework.beans.factory.InitializingBean;

/**
 * Created by admin on 2018/3/1.
 */
public class Init implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("正在执行初始化方法 afterPropertiesSet()");
    }

    public void init(){
        System.out.println("正在使用init-method属性指定初始化方法 init()");
    }
}

测试程序:

package com.custle.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by admin on 2018/3/1.
 */
public class BeanFactory {
    public static void main(String[] args) {
        ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
        act.getBean("init");
    }
}

程序输出:

正在执行初始化方法 afterPropertiesSet()
正在使用init-method属性指定初始化方法 init()

 可以看见,当同时使用这两种方式初始化方法时,先执行InitializingBean接口中定义的方法,然后执行init-method属性指定的方法。使用InitializingBean接口的方式代码耦合性较高。

    二、Bean销毁之前的行为

    与定制初始化行为相似,Spring也提供了两种方式定制Bean销毁之前的特定行为,这两种方式如下:

    第一:在xml中配置<bean>时使用destory-method属性;

    第二:实现DisposableBean接口;

    <!--使用destory-method指定Bean销毁前执行方法-->
	<bean id="destory" class="com.custle.spring.Destory" destroy-method="close"/>
package com.custle.spring;

import org.springframework.beans.factory.DisposableBean;

/**
 * Created by admin on 2018/3/1.
 */
public class Destory implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("正在通过实现DisposableBean接口执行Bean销毁前的destroy()方法");
    }

    public void close(){
        System.out.println("正在通过destory-method执行Bean销毁前的close()方法");
    }
}

测试程序:

package com.custle.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by admin on 2018/3/1.
 */
public class BeanFactory {
    public static void main(String[] args) {
        ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
        act.getBean("destory");
    }
}

控制台输出:

正在使用init-method属性指定初始化方法 init()

可以看见当同时使用这两种方式执行Bean销毁前行为时,只有通过init-method属性配置的方式生效了。这是为什么呢?单列Bean的生命周期随着Spring容器的关闭而销毁,如果在一个非WEB应用环境下,为了让Spring容器优雅的关闭,并调用singleton Bean上相应的析构回调方法,则需要在JVM中注册一个关闭钩子,这样就可以保证Spring容器被恰当关闭。

使用如下测试程序:

package com.custle.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by admin on 2018/3/1.
 */
public class BeanFactory {
    public static void main(String[] args) {
        AbstractApplicationContext act = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
        act.getBean("destory");
        act.registerShutdownHook();
    }
}

控制台输出:

正在通过实现DisposableBean接口执行Bean销毁前的destroy()方法
正在通过destory-method执行Bean销毁前的close()方法

可以看见当这两种方式同时执行时,通过实现DisposableBean接口执行销毁Bean前的行为优先级更高。

    除此之外,如果容器中很多Bean都需要指定特定的生命周期行为,则可以在<beans>中设置default-init-method属性和default-destory-method属性,它们的作用和init-method、destory-method属性类似,只不过它们是对该<beans>下所有的bean都生效。

    当Bean实现了ApplicationContextAware接口、BeanNameAware接口之后,Spring容器会在该Bean初始化完成之后--也就是调用init-method属性所指定的方法(如果有)之后,再回调setApplicationConetext(ApplicationContext applicationConext)、setBeanName(String name)方法。

猜你喜欢

转载自my.oschina.net/u/3697923/blog/1627103