【Spring 源码学习系列】ApplicationContextAware 方法的调用时机

简介: 在实际业务开发中,经常借助 ApplicationContextAware 获取 ApplicationContext 然后构造业务枚举到处理 Bean 的策略模式映射。那么,不知道大家是否都了解 `setApplicationContext `的调用时机呢?本文结合一个简单示例分析一下,这里强烈建议大家自己动手调试一下,印象会更加深刻。

一、背景

在实际业务开发中,经常借助 ApplicationContextAware 获取 ApplicationContext 然后构造业务枚举到处理 Bean 的策略模式映射。

参见:《巧用 Spring 自动注入实现策略模式升级版》

@Service
public class DemoService implements ApplicationContextAware {


    private Map<String, List<Handler>> type2HandlersMap;

    public void test(){
      String type ="Vip";
      for(Handler handler : type2HandlersMap.get(type)){
          handler.someThing();;
      }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        Map<String, Handler> beansOfType = applicationContext.getBeansOfType(Handler.class);
        beansOfType.forEach((k,v)->{
            type2HandlersMap = new HashMap<>();
            String type =v.getType();
            type2HandlersMap.putIfAbsent(type,new ArrayList<>());
            type2HandlersMap.get(type).add(v);
        });
    }
}

那么,不知道大家是否都了解 setApplicationContext 的调用时机呢?
本文结合一个简单示例分析一下,这里强烈建议大家自己动手调试一下,印象会更加深刻。

二、案例分析

定义 AwaredTestBean 实现 ApplicationContextAware 接口。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.stream.Stream;

@Component
public class AwaredTestBean implements ApplicationContextAware {
    private ApplicationContext ctx;

    public void printBeanNames() {
        Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
    // 此处断点
        this.ctx = ctx;
    }
}

基于注解编写 Configuration


import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("org.example.aware.bean")
public class AwareConfiguration {

}

构建 AnnotationConfigApplicationContext 进行测试:

import org.example.aware.bean.AwaredTestBean;
import org.example.aware.config.AwareConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AwareApplication {

    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AwareConfiguration.class);
        AwaredTestBean atBean = ctx.getBean(AwaredTestBean.class);
        atBean.printBeanNames();
    }
}

源码学习的方法有很多,可以参考我的 《如何高效学习和阅读源码?》《如何读源码更有效--直播》 等文章。

本文直接断点调试,看调用栈。

21.jpg

从入口往下梳理:
AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        register(componentClasses);
        refresh();
    }

这里的 refresh 方法是 AbstractApplicationContext#refresh 方法,是 IOC 容器启动时最核心的方法:

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            //1 初始化前的准备
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            //2 获取 BeanFactory,加载所有 bean 的定义信息(未实例化)
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            // 3 BeanFactory 的预处理配置
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 4. 准备 BeanFactory 完成后进行的后置处理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                 // 5. 执行 BeanFactory 创建后的后置处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 6. 注册 Bean 的后置处理器
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                // 7. 初始化MessageSource
                initMessageSource();

                // Initialize event multicaster for this context.
                 // 8. 初始化事件派发器
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                 // 9. 子类的多态 onRefresh
                onRefresh();

                // Check for listener beans and register them.
                 // 10. 监听器检查和注册
                registerListeners();
                // ------- BeanFactory已创建完成 --------

                // Instantiate all remaining (non-lazy-init) singletons.
                 // 11. 初始化所有剩下的单例Bean(非懒加载的)
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event. 
                // 12. 完成容器的创建工作(发布相应的事件)
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                // 销毁已经创建的单例避免浪费资源
                destroyBeans();

                // Reset 'active' flag.
                // 重置  active 标记
                cancelRefresh(ex);

                // Propagate exception to caller.
                // 异常抛给调用方
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                //13 清理缓存
                resetCommonCaches();
            }
        }
    }

在 “11. 初始化所有剩下的单例Bean(非懒加载的)” 这个环节注入的 ApplicationContext, 此时 BeanFactory 已经初始化完成。
AbstractApplicationContext#finishBeanFactoryInitialization

22.jpg
执行到预初始化单例 bean DefaultListableBeanFactory#preInstantiateSingletons

23.jpg

执行 Bean 的创建 AbstractBeanFactory#getBean(java.lang.String)

33.jpg
创建单例 Bean DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

24.jpg

AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

26.jpg
实际初始化 Bean 实例:

/**
     * Actually create the specified bean. Pre-creation processing has already happened
     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
     * <p>Differentiates between default bean instantiation, use of a
     * factory method, and autowiring a constructor.
     * @param beanName the name of the bean
     * @param mbd the merged bean definition for the bean
     * @param args explicit arguments to use for constructor or factory method invocation
     * @return a new instance of the bean
     * @throws BeanCreationException if the bean could not be created
     * @see #instantiateBean
     * @see #instantiateUsingFactoryMethod
     * @see #autowireConstructor
     */
    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
        // bean 的属性填充
            populateBean(beanName, mbd, instanceWrapper);
//【重点】执行到这里!!->  初始化 Bean 实例
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

    
    // 省略部分代码

        // Register bean as disposable.
        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }
    

27.jpg
获取并执行 BeanPostProcessor AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization

    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

28.jpg

执行 ApplicationContextAwareProcessor#postProcessBeforeInitialization

@Override
    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
            return bean;
        }

        AccessControlContext acc = null;

        if (System.getSecurityManager() != null) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
        //【重点】 调用 Aware 接口
            invokeAwareInterfaces(bean);
        }

        return bean;
    }

调用Bean 实现的 Aware 接口 ApplicationContextAwareProcessor#invokeAwareInterfaces


源码:
    private void invokeAwareInterfaces(Object bean) {
        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);
        }
    }

从这里可以看到,会判断当前 bean 是否实现了这些 Aware 接口,如果实现了这些接口,那么将 applicationContext 自身 或者 通过 applicationContext 获取所需的参数类型传递过去。


这里顺便说个调试技巧,可以 “Reset Frame” 或者 “Drop Frame” 回退到上一层,不断回退。

29.jpg

三、总结

纸上得来终觉浅,觉知此事需躬行。
希望大家可以参考本文的简单 Demo ,亲自动手调试,理解才能更深刻。

学习贵能举一反三。大家能够结合本节所学的方法自行分析 BeanNameAware 方法的调用时机呢?

本文并没有对 IOC容器启动时的最核心方法 AbstractApplicationContext 中的 refresh 进行彻底的剖析,只是结合一个具体案例从某个切面去学习其中的某个环节,大家可以通过更多案例讲整个 refresh 核心方法都串起来,理解会越来越深入。


创作不易,如果本文对你有帮助,欢迎点赞、收藏加关注,你的支持和鼓励,是我创作的最大动力。
在这里插入图片描述
相关文章
|
5天前
|
搜索推荐 JavaScript Java
基于springboot的儿童家长教育能力提升学习系统
本系统聚焦儿童家长教育能力提升,针对家庭教育中理念混乱、时间不足、个性化服务缺失等问题,构建科学、系统、个性化的在线学习平台。融合Spring Boot、Vue等先进技术,整合优质教育资源,提供高效便捷的学习路径,助力家长掌握科学育儿方法,促进儿童全面健康发展,推动家庭和谐与社会进步。
|
7月前
|
监控 Java 应用服务中间件
微服务——SpringBoot使用归纳——为什么学习Spring Boot
本文主要探讨为什么学习Spring Boot。从Spring官方定位来看,Spring Boot旨在快速启动和运行项目,简化配置与编码。其优点包括:1) 良好的基因,继承了Spring框架的优点;2) 简化编码,通过starter依赖减少手动配置;3) 简化配置,采用Java Config方式替代繁琐的XML配置;4) 简化部署,内嵌Tomcat支持一键式启动;5) 简化监控,提供运行期性能参数获取功能。此外,从未来发展趋势看,微服务架构逐渐成为主流,而Spring Boot作为官方推荐技术,与Spring Cloud配合使用,将成为未来发展的重要方向。
221 0
微服务——SpringBoot使用归纳——为什么学习Spring Boot
|
2月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
6月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
410 70
|
4月前
|
安全 Java 数据库
Spring Boot 框架深入学习示例教程详解
本教程深入讲解Spring Boot框架,先介绍其基础概念与优势,如自动配置、独立运行等。通过搭建项目、配置数据库等步骤展示技术方案,并结合RESTful API开发实例帮助学习。内容涵盖环境搭建、核心组件应用(Spring MVC、Spring Data JPA、Spring Security)及示例项目——在线书店系统,助你掌握Spring Boot开发全流程。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
516 2
|
11月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
280 2
|
6月前
|
Java Spring
Spring框架的学习与应用
总的来说,Spring框架是Java开发中的一把强大的工具。通过理解其核心概念,通过实践来学习和掌握,你可以充分利用Spring框架的强大功能,提高你的开发效率和代码质量。
153 20
|
6月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
576 5
|
6月前
|
Java Spring 容器
两种Spring Boot 项目启动自动执行方法的实现方式
在Spring Boot项目启动后执行特定代码的实际应用场景中,可通过实现`ApplicationRunner`或`CommandLineRunner`接口完成初始化操作,如系统常量或配置加载。两者均支持通过`@Order`注解控制执行顺序,值越小优先级越高。区别在于参数接收方式:`CommandLineRunner`使用字符串数组,而`ApplicationRunner`采用`ApplicationArguments`对象。注意,`@Order`仅影响Bean执行顺序,不影响加载顺序。
488 2