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

简介: 一文带你深入理解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。image.png

名称 用途 所属容器 回调点
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. 执行结果

image.png

image.png

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


源码解析


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

image.png

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

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

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

image.png

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

image.png

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

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

image.png

image.png

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

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

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

image.png


总结


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

1671110021709.jpg

BeanFactory初始化容器方式

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

ApplicationContext初始化容器方式

  1. 调用BeanFactory方式的3个Aware接口;
  2. 在加载bean之前创建一个ApplicationContextAwareProcessor,注册在AbstractBeanFactorybeanPostProcessors属性中。然后在加载bean的步骤中,调用bean后处理器的postProcessBeforeInitialization方法过程中,回调表格中的6个Aware接口。
目录
相关文章
|
存储 缓存 监控
美团面试:说说OOM三大场景和解决方案? (绝对史上最全)
小伙伴们,有没有遇到过程序突然崩溃,然后抛出一个OutOfMemoryError的异常?这就是我们俗称的OOM,也就是内存溢出 本文来带大家学习Java OOM的三大经典场景以及解决方案,保证让你有所收获!
6404 1
美团面试:说说OOM三大场景和解决方案? (绝对史上最全)
|
传感器 Java API
Spring揭秘:Aware接口应用场景及实现原理!
Aware接口赋予了Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContext、BeanFactory等。 这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性,从而让Spring的IoC容器变得更加强大和灵活。
569 0
Spring揭秘:Aware接口应用场景及实现原理!
|
Java
JVM之本地内存以及元空间,直接内存的详细解析
JVM之本地内存以及元空间,直接内存的详细解析
1293 0
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
1153 1
|
缓存 监控 安全
Spring AOP 详细深入讲解+代码示例
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。 在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。 切点是一个表达式,用于匹配目标对象的一组方法,在这些方法执行时切面会被触发。增强则定义了切面在目标对象方法执行前、执行后或抛出异常时所
17437 4
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
2099 25
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
XML 设计模式 Java
这6种 Spring 依赖注入方式,你都会吗?
这6种 Spring 依赖注入方式,你都会吗?
2291 1
这6种 Spring 依赖注入方式,你都会吗?
|
Java 编译器 Spring
面试突击78:@Autowired 和 @Resource 有什么区别?
面试突击78:@Autowired 和 @Resource 有什么区别?
16741 6
|
XML Java 程序员
保姆级教程,手把手教你实现SpringBoot自定义starter
保姆级教程,手把手教你实现SpringBoot自定义starter
13959 2
保姆级教程,手把手教你实现SpringBoot自定义starter
|
XML Java 测试技术
Graalvm 替代 JVM 真的可以带来巨大的性能优势吗?
介绍 Spring Boot有助于轻松开发独立的、可用于生产的 Spring 应用程序。它对 Spring 平台和第三方库采用固执己见的方法:以最少的配置简化设置过程。优势: 易于使用:Spring Boot 简化了独立 Spring 应用程序的创建,无需复杂的配置。 嵌入式服务器:它允许直接嵌入 Tomcat、Jetty 或 Undertow 等服务器,从而无需单独部署 WAR 文件。 Starter 依赖项:Spring Boot 提供预配置的“starter”依赖项,降低了构建配置的复杂性。 自动配置:Spring Boot 自动配置 Spring 和第三方库,最大限度地减少手动设置工