Spring关于@Configuration配置处理流程解析

@Configuration配置处理流程解析

  • AnnotationConfigApplicationContext基于注解配置
  • ApplicationContext启动刷新流程
  • Spring关于@Configuration解析处理流程
  • 那些年被忽略问题

AnnotationConfigApplicationContext基于注解配置

Spring通过上下文应用AnnotationConfigApplicationContext提供基于注解配置能力,启动过程中通过ConfigurationClassPostProcessor在执行Bean定义注册后处理器阶段解析@Configuration、@Bean、@Import等注解,完成Bean声明定义和注册到容器注册器中。本文简述Spring容器启动流程对配置类@Configuration处理过程,理解Spring应用如何实现基于@Configuration配置注册。

ApplicationContext启动刷新流程

Spring容器启动流程AbstractApplicationContext#refresh,列举几个关键阶段(感兴趣同学自行debug):

  1. obtainFreshBeanFactory,获取Bean工厂。
  2. prepareBeanFactory,准备工作,设置系统相关Bean定义等。
  3. postProcessBeanFactory,设置Bean工厂后处理。
  4. invokeBeanFactoryPostProcessors,执行Bean工厂后置处理器,按Bean定义注册器后处理,Bean工厂后置处理顺序执行。
  5. registerBeanPostProcessors,注册Bean后处理器。
  6. initMessageSource、initApplicationEventMulticaster,初始化国际化消息和Spring事件广播处理器。
  7. registerListeners,注册监听器。
  8. finishBeanFactoryInitialization,固化配置,完成单例非延迟初始化对象实例化。

Spring关于@Configuration解析处理流程

上面第4点,Spring可以通过自定义Bean定义后置处理,自定义解析Bean定义规则并完成Bean定义注册到Spring容器中,@Configuration就是通过bean定义注册后置处理器ConfigurationClassPostProcessor实现,关键处理步骤如下(感兴趣同学自行debug):

  1. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry,Bean定义后置处理器执行入口。
  2. ConfigurationClassPostProcessor#processConfigBeanDefinitions,通过扫描应用已注册配置,引导扫描或导入其他候选配置类。
  3. ConfigurationClassParser#parse,解析每一个配置类,按如下顺序处理,具体代码见:
    ConfigurationClassParser#doProcessConfigurationClass
    1)、获取配置类内部定义的成员类,即静态内部类和实例内部类,如果内部成员类为配置类,则递归处理内部成员类。
    2)、处理配置类上面@PropertySource注解,属性文件注入处理。
    3)、扫描@ComponentScan @ComponentScans指定路径下Component类(ComponentScanAnnotationParser#parse),如果扫描类为配置类,则递归处理扫描到的类。
    4)、处理@Import,导入指定配置类,导入方式分ImportSelector,ImportBeanDefinitionRegistrar和processConfigurationClass。
    5)、处理@ImportResource,导入指定配置资源文件。
    6)、处理配置类内部定义的@Bean methods
    7)、处理default methods on interfaces
    8)、处理superClass
  4. ConfigurationClassBeanDefinitionReader#loadBeanDefinitions,加载3解析出来@Bean,对于静态方法Bean和实例方法Bean定义区别,需要关注ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod。

那些年被忽略问题

基于对配置类@Configuration处理流程理解,试下是否能正确回答下面两个问题:
问题 1:@Configuration配置类实例方法声明@Bean和静态方法声明@Bean有什么区别,对应用启动有产生什么影响?
样例代码如下:

@Configuration
public class UserConfiguration {@Beanpublic static UserService userService() {return new UserService();}/*@Beanpublic UserService userService() {return new UserService();}*/
}@Data
public class UserService {public String sayHello() {return "hello";}
}

解析 1:从@Configuration解析处理流程可以知道,@Bean方法在ConfigurationClassBeanDefinitionReader#loadBeanDefinitions中通过包装成工厂方法去声明Bean定义,实例方法调用需要依赖于类实例对象,故会触发类实例化,而静态方法不需要依赖于实例对象,故不会触发类实例化。故如果是类实例方法声明@Bean,会导致工厂配置类过早实例化,从会引起不可预期异常。
关于这点,Spring官方明确说明:https://docs.spring.io/spring-framework/reference/core/beans/java/composing-configuration-classes.html
在这里插入图片描述

  1. @Configuration配置类依赖应该简单,因为配置类实例化可能会提前,依赖注入关系会导致非预期异常。
  2. @Configuration如果有定义bean工厂后处理器和bean后处理器,应该声明为静态@Bean方法,避免导致配置类过早实例化。

问题 2: @Configuration配置类内部实例类和内部静态类内声明Bean,Bean实例化顺序是什么?
样例代码如下:

@Configuration
public class UserOuterConfiguration {@Beanpublic UserService userService1() {return new UserService("userService1");}@Configurationpublic static class UserInnerConfiguration {@Beanpublic UserService userService2() {return new UserService("userService2");}}
}@Data
@AllArgsConstructor
public static class UserService {private String name;public String sayHello() {return "hello";}
}

解析2:在组件扫描ComponentScan处理候选Configuration,会扫描指定包名下的配置类,按名称字典序排序。这个会让内部配置类优先与配置类处理,bean实例化顺序依赖于bean注册器里面注册的顺序,所以在不存在依赖关系,即没有如@Autoware @DependsOn @Lazy等会影响bean实例化顺序和Import导入配置类等改变某个配置处理顺序前提下,内部静态配置类定义Bean的实例化会优先于外部配置类定义Bean实例化。

by 三木

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/1312.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL-SQL存储过程/触发器详解(下)

♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏&#xf…

启动spring boot项目时加载配置文件报错的问题

最近把电脑重置了一下,然后重新安装各种软件,从gitee拉去项目到本地运行时居然启动报错了 Failed to load property source from file:/D:/program/IdeaProjects/layui/target/classes/application.yml 这是加载配置文件的时候失败了,提示一堆…

Mybatis-Plus:实现自定义SQL

目录 1.简介 2.自定义SQL具体实现 2.1.注解SQL 2.2.Wrapper传参注解SQL 2.3.Wrapper传参xml文件SQL 2.4.正常传参XML文件SQL 3.总结 1.简介 Mybatis-Plus(以下简称MBP)的初衷是为了简化开发,而不建议开发者自己写SQL语句的&#xff1b…

华为云CodeArts TestPlan测试设计:守护产品开发质量之魂

华为产品质量的守护神 华为云CodeArts TestPlan测试设计是华为产品质量的守护神。华为云CodeArts TestPlan提供多维度测试设计模板、“需求-场景-测试点-测试用例” 四层测试分解设计能力,启发测试人员发散性思维,对项目环境、测试对象、质量标准、测试…

深入理解 Golang: Goroutine 协程

进程用来分配内存空间,是操作系统分配资源的最小单位;线程用来分配 CPU 时间,多个线程共享内存空间,是操作系统或 CPU 调度的最小单位;协程用来精细利用线程。协程就是将一段程序的运行状态打包,可以在线程…

java之路——带你了解Hibernate与基本过程

文章目录 前言一、Hibernate用来干嘛的二、Hibernate与mybatisHibernate的基本开发步骤 前言 Hibernate框架的发展可以追溯到2001年,它在过去的几年里获得了广泛的应用和持续的发展。 其中的发展演变: 初期版本(2001-2006年)&am…

css基础知识十:介绍一下CSS中的Grid网格布局?

一、是什么 Grid 布局即网格布局,是一个二维的布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列 擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系 这与之前讲到的flex一维…

【单片机】STM32F103C8T6 最小系统板原理图

STM32F103C8T6是一款基于ARM Cortex-M3内核的32位微控制器,由STMicroelectronics(ST)公司生产。它是STMicroelectronics的STM32系列微控制器中的一员,被广泛应用于嵌入式系统和电子设备中。 STM32F103C8T6单片机的主要特点和资源…

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境

Windows11安装oneAPI和Visual Studio 2022配置Fortran并行环境 安装Visual Studio 2022 Community安装oneAPI建立Fortran工程项目测试建立单核运行的Fortran运行算例建立并行运行的Fortran运行算例 结语 安装Visual Studio 2022 Community 访问微软Visual Studio官网&#xff…

二叉树题目:单值二叉树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题:单值二叉树 出处:965. 单值二叉树 难度 3 级 题目描述 要求 如果二叉树每个结点都具有相同的值&am…

【Solr】中文分词配置

提示:在设置中文分词前需确保已经生成过core,未生成core的可以使用:solr create -c "自定义名称"进行定义。 未分词前的效果预览: 下载分词器: 下载地址: https://mvnrepository.com/artifact/com.github.m…

网络安全能力成熟度模型介绍

一、概述 经过多年网络安全工作,一直缺乏网络安全的整体视角,网络安全的全貌到底是什么,一直挺迷惑的。目前网络安全的分类和厂家非常多,而且每年还会冒出来不少新的产品。但这些产品感觉还是像盲人摸象,只看到网络安…