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

概述

想必大家在看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。一文带你深入理解SpringBean生命周期之Aware详解

名称 用途 所属容器 回调点
BeanNameAware 获取bean名称 BeanFactory Bean后处理器的BeforeInitialization方法之前
BeanClassLoaderAware 获取bean的类加载器 BeanFactory Bean后处理器的BeforeInitialization方法之前
BeanFactoryAware 获取bean工厂(建议用下面的ApplicationContextAware) BeanFactory Bean后处理器的BeforeInitialization方法之前
EnvironmentAware 获取环境相关信息,如属性、配置信息等 ApplicationContext Bean后处理器的BeforeInitialization方法中
EmbeddedValueResolverAware 获取值解析器 ApplicationContext Bean后处理器的BeforeInitialization方法中
ResourceLoaderAware 获取资源加载器 ApplicationContext Bean后处理器的BeforeInitialization方法中
ApplicationEventPublisherAware 获取事件广播器,发布事件使用 ApplicationContext Bean后处理器的BeforeInitialization方法中
MessageSourceAware 获取消息资源 ApplicationContext Bean后处理器的BeforeInitialization方法中
ApplicationContextAware 获取ApplicationContext ApplicationContext Bean后处理器的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. 执行结果
一文带你深入理解SpringBean生命周期之Aware详解
一文带你深入理解SpringBean生命周期之Aware详解

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

源码解析

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

总结

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

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

BeanFactory初始化容器方式

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

ApplicationContext初始化容器方式

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


参考

https://blog.csdn.net/Bronze5/article/details/105902892

https://juejin.cn/post/6844903938131509256


原文始发于微信公众号(JAVA旭阳):一文带你深入理解SpringBean生命周期之Aware详解

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/63847.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!