一文带你深入理解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接口。
目录
相关文章
|
设计模式 监控 安全
JUC第一讲:Java并发知识体系详解 + 面试题汇总(P6熟练 P7精通)
JUC第一讲:Java并发知识体系详解 + 面试题汇总(P6熟练 P7精通)
4895 0
|
6月前
|
关系型数据库 MySQL Java
分布式事务终极指南:2PC/XA/TCC/SAGA 从底层原理到生产选型全拆解
本文系统解析分布式事务四大主流方案:XA/2PC(强一致但性能差)、TCC(高并发柔性事务)、SAGA(长事务最终一致)及理论基石(ACID/CAP/BASE),涵盖原理、流程、实战代码、优劣对比与生产选型标准,助你深入掌握核心逻辑。
1253 3
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
3798 7
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
461 4
|
缓存 监控 安全
Spring AOP 详细深入讲解+代码示例
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。 在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。 切点是一个表达式,用于匹配目标对象的一组方法,在这些方法执行时切面会被触发。增强则定义了切面在目标对象方法执行前、执行后或抛出异常时所
18202 5
|
Prometheus 监控 Cloud Native
高频面题: 你们线上 QPS 多少?你 怎么知道的?
本文由45岁资深架构师尼恩撰写,针对高级开发和架构师面试中的高频问题提供详细解答。文章涵盖了QPS、TPS、RT等性能指标的定义及计算方法,详解了如何配置Prometheus与Grafana监控系统QPS,并提供了应对高并发场景(如双十一抢购)的系统部署策略。此外,还分享了多个大厂面试真题及解决方案,帮助读者在面试中充分展示技术实力,提升求职竞争力。建议收藏并深入学习,为面试做好充分准备。更多内容可参考《尼恩Java面试宝典》及相关技术圣经系列PDF。
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
751 0
|
消息中间件 编解码 网络协议
Netty从入门到精通:高性能网络编程的进阶之路
【11月更文挑战第17天】Netty是一个基于Java NIO(Non-blocking I/O)的高性能、异步事件驱动的网络应用框架。使用Netty,开发者可以快速、高效地开发可扩展的网络服务器和客户端程序。本文将带您从Netty的背景、业务场景、功能点、解决问题的关键、底层原理实现,到编写一个详细的Java示例,全面了解Netty,帮助您从入门到精通。
3200 0
|
消息中间件 负载均衡 Kafka
Kafka的ISR和OSR的作用分别是什么
Kafka的ISR和OSR的作用分别是什么
1453 3
|
存储 缓存 算法
这些年背过的面试题——Netty篇
本文是技术人面试系列Netty篇,面试中关于Netty都需要了解哪些基础?一文带你详细了解,欢迎收藏!