Spring 中Bean的生命周期

2019-06-26  本文已影响0人  757a

Bean的生命周期

Bean 的生命周期是指在 IOC 容器中, 一个 Bean 从初始化到销毁的整个过程.

生命周期

一、Aware 接口

Aware 接口是 Spring 提供的可用于自定义 Bean 特性的接口。

ApplicationContextAware

为实现类添加 applicationContext 对象引用.

可以将引用转换(向下转型)为此接口的已知子类(例如: ConfigurableApplicationContext)以编程方式操纵它们的方法。另一种用途是手动获取其他Bean对象。

ApplicationContextAware 接口的定义:

public interface ApplicationContextAware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

例子:

public class DemoApplicationContextAware implements ApplicationContextAware {
    private ConfigurableApplicationContext applicationContext;
    
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
        // 强制转换(向下转型)
        this.applicationContext = (ConfigurableApplicationContext) applicationContext;
       
        // 程序内获取配置信息. 可以动态改变程序的功能和运行状态.
        configContext.getEnvironment().getProperty("spring.profiles.active");
    }
    
}

BeanNameAware

为实现类提供其关联对象中定义的名称的引用.

ps: 个人理解, 提供该对象在 IOC 容器中的名称.

BeanNameAware 接口的定义:

public interface BeanNameAware {

    void setBeanName(String name) throws BeansException;
}

例子:

public class Person implements BeanNameAware {

    public void setBeanName(String name) throws BeansException{
        System.out.println(name);
        // out: person
    }
}

其他 Aware 及其功能

名称 注入依赖 DOCS
ApplicationContextAware 声明ApplicationContext。 ApplicationContextAware and BeanNameAware
ApplicationEventPublisherAware 封闭的事件发布者ApplicationContext。 附加功能 ApplicationContext
BeanClassLoaderAware 用于加载bean的类加载器。 实例化Bean
BeanFactoryAware 声明BeanFactory ApplicationContextAware and BeanNameAware
BeanNameAware 声明bean的名称。 ApplicationContextAware and BeanNameAware
BootstrapContextAware 容器运行的资源适配器BootstrapContext。通常仅在支持JCA的ApplicationContext实例中可用。 JCA CCI
LoadTimeWeaverAware 定义编织器用于在加载时处理类定义。 在Spring框架中使用AspectJ进行加载时编织
MessageSourceAware 用于解析消息的已配置策略(支持参数化和国际化)。 附加功能 ApplicationContext
NotificationPublisherAware Spring JMX通知发布者。 通知
ResourceLoaderAware 配置资源的加载程序,用于对资源进行低级访问。 资源
ServletConfigAware 容器当前运行的 ServletConfig。仅在Web感知的Spring ApplicationContext中有效。 Spring MVC
ServletContextAware 容器当前运行的 ServletContext。仅在Web感知的Spring ApplicationContext中有效。 Spring MVC

二、Bean的初始化与销毁

对象的初始化发生在对象属性设置之后(意味着已经完成实例化, 并且已对属性赋值).
销毁发生在容器关闭前(应用程序关闭前).

Spring 提供了三种初始化/销毁 Bean 的方式.

若定义了多种初始化方法, 但方法名称相同, 将只调用一次. 同理销毁方法也一样.

基于 @PostConstruct、@PreDestory 注解

@PostConstruct、@PreDestory 是 JSR-250 定义的生命周期注解.
可用于标记任意 ‘无参数’ 的方法.

例子:

public class Person {
    /**
    * 生命周期注解 @PostConstruct,在实例化之后执行
    */
    @PostConstruct
    public void instantiationAfter() {
    
    }
    
    /**
    * 生命周期注解 @PreDestory,在销毁之前执行
    */
    @PreDestory
    public void destoryBefore() {
    
    }
}

基于XML或Java配置

init-method、destory-method 属性可以指定任意 ‘无参数’ 的方法名称.

XML 配置:

<bean id="person" class="lifecycle.Person" init-method="init" destory-method="destory"/>

或 Java 配置类:

@Bean(initMethod = "init", destoryMethod = "destory")
public Person person(){
    return new Person();
}

例子:

public class Person {
    /**
    * 由 init-method 指定的自定义方法
    */
    private void init() {
    
    }
    
    /**
    * 由 destory-method 指定的自定义方法
    */
    private void destory() {
    
    }
}

实现 InitializingBean、DisposableBean 接口

InitializingBean 定义了一个方法, Spring 会在对象属性设置后, 回调此方法:

void afterPropertiesSet() throws Exception;

DisposableBean 也定义了一个方法, Spring 会在容器销毁前, 回调此方法:

void destory() throws Exception;

注: Spring官方出于解耦的原因, 不建议通过这两个接口进行初始化、销毁操作.

例子:

public class Person implements InitializingBean, DisposableBean {
    /**
     * 实现 InitializingBean 的初始化方法
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception{
        
    }
    
    /**
     * 实现 DisposableBean 的初始化方法
     *
     * @throws Exception
     */
    @Override
    public void destory() throws Exception{
        
    }
}

三、BeanPostProcessor Bean后置处理器

BeanPostProcessor 接口定义了可以自定义实现的回调方法,以提供自定义的(或覆盖容器的)实例化逻辑和依赖关系解析逻辑等。
如果要在 Spring 容器完成实例化,配置和初始化 bean 之后实现某些自定义逻辑,则可以插入一个或多个自定义 BeanPostProcessor 实现。

您可以配置多个 BeanPostProcessor 实例,并且可以通过 Ordered 接口设置 order 来控制这些实例的执行顺序。

实现 BeanPostProcessor 接口的类是特殊的,容器会对它们进行不同的处理。BeanPostProcessor 直接引用的所有实例和 bean 都会在启动时实例化,作为 ApplicationContext 特殊启动阶段的一部分。
接下来,所有 BeanPostProcessor 实例都以排序方式注册,并应用于容器中的所有其他 bean (以编程方式注册的 BeanPostProcessor 实例始终在自动检测注册的 BeanPostProcessor 实例之前处理,不管任何显式排序)。
另外, AOP 也是通过 BeanPostProcessor 实现的, 所以 BeanPostProcessor 实例和它们直接引用的 bean 都不符合自动代理的条件.

BeanPostProcessor 接口定义:

public interface BeanPostProcessor {

    /**
    * bean 初始化之前执行.
    **/
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    
    /**
    * bean 初始化之后执行.
    **/
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

ApplicationContextAwareProcessor 源码实例

ApplicationContextAware 接口的检查也是通过 BeanPostProcessor 实现的. 这也能解释为什么 Aware 在初始化之前执行.

class ApplicationContextAwareProcessor implements BeanPostProcessor {

    private final ConfigurableApplicationContext applicationContext;

    private final StringValueResolver embeddedValueResolver;


    /**
     * 为不同的 applicationContext 创建 ApplicationContextAwareProcessor.
     */
    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }


    @Override
    @Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;
        
    ---- 偏离标题 略过...
        // 检查 Java安全管理器 和 匹配给定的 Aware 接口
        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            // 若开启 Java安全管理器, 获取访问控制上下文
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            // 开启 Java安全管理器的情况下需要为不可信的外部代码进行提权操作.
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
    ----
        else {
            // 根据 Aware 接口类型调用对应的接口方法.
            invokeAwareInterfaces(bean);
        }

        return bean;
    }
    
    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }

}

附 生命周期demo

spring lifecycle demo - github

Demo 输出结果:

Person 类通过 'Person()' 实例化  
Aware方法:'BeanNameAware' 的 'setBeanName()' 方法。  
Aware方法:'ApplicationContextAware' 的 'setApplicationContext()' 方法。  
初始化之前执行。Class: Person. Bean Name: person  
初始化方法:'@PostConstruct' 的 'instantiationAfter()' 方法。  
初始化方法:'InitializingBean' 的 'afterPropertiesSet()' 方法。  
初始化方法:'init-method' 的 'customInitMethod()' 方法。  
初始化之后执行。Class: Person. Bean Name: person  
销毁方法:'@PreDestroy' 的 'destroyBefore()' 方法。  
销毁方法:'DisposableBean' 的 'destroy()' 方法。  
销毁方法:'destroy-method' 的 'customDestroyMethod()' 方法。  

参考

Spring core文档 1.6节、1.8节

上一篇下一篇

猜你喜欢

热点阅读