一文带你深入理解SpringBean生命周期之Aware详解

3,288 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

诺兰给了我们一场无法盗取的梦。

概述

相比大家在看Spring的源码看到很多实现了Aware接口的类,比如实现了BeanNameAware, BeanFactoryAware等。那这一些列的Aware接口用什么作用呢?他们又是在什么时候调用的呢?一切答案将在本篇文章中为大家揭晓。

Aware接口介绍

/**
 * A marker superinterface indicating that a bean is eligible to be notified by the
 * Spring container of a particular framework object through a callback-style method.
 * The actual method signature is determined by individual subinterfaces but should
 * typically consist of just one void-returning method that accepts a single argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default functionality.
 * Rather, processing must be done explicitly, for example in a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * for an example of processing specific {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface Aware {

}

上面是Aware接口的源码定义,我们先来看下他的注释,Spring的注释还是写的非常不错的,我们翻译下:

Aware 接口是一个具有标识作用的超级接口,指示 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回调的方式。Aware 接口是一个空接口,具体的实现由各个子接口决定,且该接口通常只包含一个单个参数并且返回值为void的方法。可以理解就是 set 方法。该方法的命名方式为 set + 去掉接口名中的 Aware 后缀,即 XxxAware 接口,则方法定义为 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。注意,仅实现Aware接口,不会提供任何默认功能,需要明确的指定实现哪个子接口

通俗的来说,Aware翻译过来的意思是有感知的,察觉的,如果类上实现了该接口,表明对什么有感知,比如BeanNameAware, 表示知道了自己的Bean Name。

作用

为什么要有个Aware接口?

因为我们在实际的开发过程中,有些Bean可能需要用到Spring容器本身的功能资源,所以Spring容器中的Bean此时就要意识到Spring容器的存在才能调用Spring所提供的资源。我们通过Spring提供的一系列接口Spring Aware来实现具体的功能。

内置的Aware

我们可以看到Spring内置了很多的Aware。

名称用途所属容器回调点
BeanNameAware获取bean名称BeanFactoryBean后处理器的BeforeInitialization方法之前
BeanClassLoaderAware获取bean的类加载器BeanFactoryBean后处理器的BeforeInitialization方法之前
BeanFactoryAware获取bean工厂(建议用下面的ApplicationContextAware)BeanFactoryBean后处理器的BeforeInitialization方法之前
EnvironmentAware获取环境相关信息,如属性、配置信息等ApplicationContextBean后处理器的BeforeInitialization方法中
EmbeddedValueResolverAware获取值解析器ApplicationContextBean后处理器的BeforeInitialization方法中
ResourceLoaderAware获取资源加载器ApplicationContextBean后处理器的BeforeInitialization方法中
ApplicationEventPublisherAware获取事件广播器,发布事件使用ApplicationContextBean后处理器的BeforeInitialization方法中
MessageSourceAware获取消息资源ApplicationContextBean后处理器的BeforeInitialization方法中
ApplicationContextAware获取ApplicationContextApplicationContextBean后处理器的BeforeInitialization方法中

实践案例

  1. 定义bean实现对应的aware接口
@Data
@Slf4j
@ToString
@Accessors(chain = true)
public class BeanLifeCycle implements InitializingBean, BeanNameAware, BeanFactoryAware, EnvironmentAware, ApplicationContextAware {

    @Value("${prop:hello}")
    private String prop ;

    private String beanName;

    private BeanFactory beanFactory;

    private ApplicationContext applicationContext;

    private Environment environment;

    public BeanLifeCycle() {
        log.info("#################BeanLifeCycle 实例化");
    }

    public void init() {
        log.info("#################BeanLifeCycle 调用init-mthod 初始化");
    }

    public void destroy() {
        log.info("#################BeanLifeCycle 销毁");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("#################BeanLifeCycle 调用afterPropertiesSet方法, 查看属性值prop:[{}],已经被赋值", prop);
        log.info("#################BeanLifeCycle 调用afterPropertiesSet 初始化");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("@@@@@@@@@@@@@@@@@@ beanFactory: [{}]", beanFactory);
    }

    @Override
    public void setBeanName(String beanName) {
        log.info("@@@@@@@@@@@@@@@@@@ beanName: [{}]", beanName);
        this.beanName = beanName;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("@@@@@@@@@@@@@@@@@@ applicationContext: [{}]", applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setEnvironment(Environment environment) {
        log.info("@@@@@@@@@@@@@@@@@@ environment: [{}]", environment);
        this.environment = environment;
    }
}
  1. 执行结果

执行结果中输出了awre接口执行的内容。

源码解析

现在我们从源码角度分析下aware接口的执行时机。

通过debug追踪到执行是在创建bean的初始化阶段。

  1. AbstractAutowireCapableBeanFactorydoCreateBean()是创建bean的入口。
  2. AbstractAutowireCapableBeanFactoryinitializeBean()方法是bean的初始化入口。

我们重点关注Bean的初始化。

可以看到有两个点回执行Aware接口,我们先看下第一个方法invokeAwareMethods()

很明显,上面标记的1,2,3分别执行BeanNameAwareBeanClassLoaderAwareBeanFactoryAware 3个接口的方法。

ApplicationContextAwareProcessor实现了BeanPostProcessor, 是Spring内置的的一个处理器,在Bean初始化化前后执行,它也是执行Aware接口的另外一个入口。

ok, 到这里我们明白了这个Aware接口的执行时机。

ApplicationContextAwareProcessor这个处理器本身是什么时候注入到容器中的呢?

是在创建容器的时候AbstractApplicationContext#refresh()方法中调用了prepareBeanFactory方法。

总结

Bean创建时,会调用Aware接口,设置容器对应的资源属性,扩展Bean的能力。

BeanFactory初始化容器方式

在加载bean的步骤中,创建bean之后,调用bean后处理器之前,回调表格中的3个Aware接口。

ApplicationContext初始化容器方式

  1. 调用BeanFactory方式的3个Aware接口;
  2. 在加载bean之前创建一个ApplicationContextAwareProcessor,注册在AbstractBeanFactorybeanPostProcessors属性中。然后在加载bean的步骤中,调用bean后处理器的postProcessBeforeInitialization方法过程中,回调表格中的6个Aware接口。


参考

blog.csdn.net/Bronze5/art…

juejin.cn/post/684490…