Spring关于@Configuration配置处理流程

 更新时间:2023年06月25日 15:44:14   作者:软件开发随心记  
这篇文章主要介绍了Spring关于@Configuration配置处理流程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

@Configuration配置处理流程解析

AnnotationConfigApplicationContext基于注解配置

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

ApplicationContext启动刷新流程

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

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

Spring关于@Configuration解析处理流程

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

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry,Bean定义后置处理器执行入口。
ConfigurationClassPostProcessor#processConfigBeanDefinitions,通过扫描应用已注册配置,引导扫描或导入其他候选配置类。
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
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions,加载3解析出来@Bean,对于静态方法Bean和实例方法Bean定义区别,需要关注ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod。

那些年被忽略问题

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

@Configuration
public class UserConfiguration {
	@Bean
	public static UserService userService() {
		return new UserService();
	}
	/*@Bean
	public 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

在这里插入图片描述

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

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

@Configuration
public class UserOuterConfiguration {
	@Bean
	public UserService userService1() {
		return new UserService("userService1");
	}
	@Configuration
	public static class UserInnerConfiguration {
		@Bean
		public 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实例化。

到此这篇关于Spring关于@Configuration配置处理流程解析的文章就介绍到这了,更多相关Spring @Configuration配置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解读Spring MVC的工作流程

    解读Spring MVC的工作流程

    SpringMVC的工作流程是基于模型-视图-控制器(MVC)设计模式的一个典型实现,主要包括用户发送请求到前端控制器(DispatcherServlet)、前端控制器转发请求给处理器映射器(HandlerMapping)
    2025-01-01
  • Google Guava 缓存工具使用详解

    Google Guava 缓存工具使用详解

    这篇文章主要介绍了Guava自加载缓存LoadingCache使用指南,通过这些内容介绍,了解了LoadingCache的基本原理和用法,包括如何创建和配置缓存,以及如何结合Java 8的特性来优化代码,需要的朋友可以参考下
    2023-12-12
  • Java中的CompletableFuture原理与用法

    Java中的CompletableFuture原理与用法

    CompletableFuture 是由Java8引入的,这让我们编写清晰可读的异步代码变得更加容易,该类功能比Future 更加强大,在Java中CompletableFuture用于异步编程,异步通常意味着非阻塞,运行任务单独的线程,与主线程隔离,这篇文章介绍CompletableFuture原理与用法,一起看看吧
    2024-01-01
  • 详解Java分布式事务的 6 种解决方案

    详解Java分布式事务的 6 种解决方案

    在分布式系统、微服务架构大行其道的今天,服务间互相调用出现失败已经成为常态,本文侧重于其他几项,关于 2PC、3PC 传统事务,网上资料已经非常多了,这里不多做重复,本文通过示例给大家介绍Java分布式事务的 6 种解决方案,一起看看吧
    2021-06-06
  • Java日常练习题,每天进步一点点(25)

    Java日常练习题,每天进步一点点(25)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-07-07
  • Springboot实现多线程及线程池监控

    Springboot实现多线程及线程池监控

    线程池的监控很重要,本文就来介绍一下Springboot实现多线程及线程池监控,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • Mybatis空值关联的具体实现

    Mybatis空值关联的具体实现

    在复杂的数据库查询中,处理空值关联是一项常见的需求,本文就来介绍一下Mybatis空值关联的具体实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-07-07
  • 将字符串数字格式化为样式1,000,000,000的方法

    将字符串数字格式化为样式1,000,000,000的方法

    这篇文章主要介绍了将字符串数字格式化为样式1,000,000,000的方法,有需要的朋友可以参考一下
    2014-01-01
  • 三分钟带你了解SpringBoot真正的启动引导类

    三分钟带你了解SpringBoot真正的启动引导类

    这篇文章主要介绍了三分钟带你了解SpringBoot真正的启动引导类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java将本地项目部署到Linux服务器的实践

    Java将本地项目部署到Linux服务器的实践

    本文主要介绍了Java将本地项目部署到Linux服务器的实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2022-06-06

最新评论