Sping源码(七)—ConfigurationClassPostProcessor创建流程

2024-04-20 04:12

本文主要是介绍Sping源码(七)—ConfigurationClassPostProcessor创建流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序言

前两篇文章介绍了invokeBeanFactoryPostProcessors的执行流程,和自定义实现BeanDefinitionRegistryPostProcessor类的方式方法。

这篇文章会主要介绍Spring启动加载xml时,ConfigurationClassPostProcessor类是如何加载到Spring中,并且看看这个类中都做了些什么。

ConfigurationClassPostProcessor这个类在Spring中非常重要,并且之后在SpringBoot中也有涉及。

component-scan

介绍ConfigurationClassPostProcessor之前就不得不说一下context component-scan标签是如何进行加载解析的。

 <context:component-scan base-package="com.xxx" ></context:component-scan>

我们在Spring中通常都用 < context:component-scan >标签来实现包的扫描,而xml在加载解析时。
如果碰到默认的 bean、beans、import、alias标签,会走一套解析流程。
除此之外,其余每个标签中的每个属性都会有单独的Parser类来进行单独的解析。

component-scan解析流程图

在这里插入图片描述

源码

通过源码来仔细看上面的每一步都做了什么。

custom标签解析流程之前帖子中都有提过,不熟悉的这篇帖子中都有介绍。

spring.handlers
加载handlers文件并转换成Map,通过key找到context对应的handler
在这里插入图片描述

ContextNamespaceHandler
执行Handler下init()方法进行初始化,创建context标签下每一个属性的Parser,解析时通过key value形式获取到具体的Parser

public class ContextNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());}
}

parseCustomElement
通过key获取到具体的Handler

@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 获取对应的命名空间String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间找到对应的NamespaceHandlerspringNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}// 调用自定义的NamespaceHandler进行解析return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}

parse
handler调用具体的parse()方法进行元素解析。

	@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取元素的解析器BeanDefinitionParser parser = findParserForElement(element, parserContext);return (parser != null ? parser.parse(element, parserContext) : null);}

ComponentScanBeanDefinitionParser
解析context标签的 component-scan元素,所以找到具体ComponentScanBeanDefinitionParser类parse方法。

public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取<context:component-scan>节点的base-package属性值String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);// 解析占位符basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);// 解析base-package(允许通过,;\t\n中的任一符号填写多个)String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);// Actually scan for bean definitions and register them.// 构建和配置ClassPathBeanDefinitionScannerClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);// 使用scanner在执行的basePackages包中执行扫描,返回已注册的bean定义Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);// 组件注册(包括注册一些内部的注解后置处理器,触发注册事件)registerComponents(parserContext.getReaderContext(), beanDefinitions, element);return null;}
}

doScan
获取base-package属性所对应的包名, 并加载所有能够被识别的Bean,封装到BeanDefinition中并注册。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();// 遍历basePackagesfor (String basePackage : basePackages) {// 扫描basePackage,将符合要求的bean定义全部找出来Set<BeanDefinition> candidates = findCandidateComponents(basePackage);// 遍历所有候选的bean定义for (BeanDefinition candidate : candidates) {// 解析@Scope注解,包括scopeName和proxyModeScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());// 使用beanName生成器来生成beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {// 处理beanDefinition对象,例如,此bean是否可以自动装配到其他bean中postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 处理定义在目标类上的通用注解,包括@Lazy,@Primary,@DependsOn,@Role,@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查beanName是否已经注册过,如果注册过,检查是否兼容if (checkCandidate(beanName, candidate)) {// 将当前遍历bean的bean定义和beanName封装成BeanDefinitionHolderBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 根据proxyMode的值,选择是否创建作用域代理definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册beanDefinitionregisterBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}

registerComponents
这个方法一共做两件事:

  1. 将上一步获取到的所有BeanDefinition添加到compositeDef的nestedComponents属性中。
  2. 判断属性annotation-config值(默认为true),如果为true,则调用AnnotationConfigUtils.registerAnnotationConfigProcessors方法。
protected void registerComponents(XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {Object source = readerContext.extractSource(element);// 使用注解的tagName和source构建CompositeComponentDefinitionCompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);// 将扫描到的所有beanDefinition添加到compositeDef的nestedComponents属性中for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));}// Register annotation config processors, if necessary.boolean annotationConfig = true;if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {// 获取component-scan标签的annotation-config属性值,默认为trueannotationConfig = Boolean.parseBoolean(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));}if (annotationConfig) {// 如果annotation-config属性值为true,在给定的注册表中注册所有用于注解的bean后置处理器Set<BeanDefinitionHolder> processorDefinitions =AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);for (BeanDefinitionHolder processorDefinition : processorDefinitions) {// 将注册的注解后置处理器的BeanDefinition添加到compositeDef的nestedComponents属性中compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));}}// 触发组件注册事件,默认实现为EmptyReaderEventListenerreaderContext.fireComponentRegistered(compositeDef);}

核心方法 AnnotationConfigUtils.registerAnnotationConfigProcessors

经过了前面一系列的加载、铺垫,此时终于来到了核心方法,来看看ConfigurationClassPostProcessor是如何进行创建的。

AnnotationConfigUtils类中有许多的常量值,而代码中会进行判断,如果没有该BeanDefinition,则会进行创建,而创建的正是ConfigurationClassPostProcessor.class

源码片段

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {//省略部分源码....
public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalConfigurationAnnotationProcessor";// 创建BeanDefinitionHolder集合Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 注册内部管理的用于处理@configuration注解的后置处理器的beanif (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);// 注册BeanDefinition到注册表中beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}return beanDefs;}

完整方法
会在类型进行多个常量判断,如果BeanDefinition中不包含该类,则创建并封装到BeanDefinition中。

public abstract class AnnotationConfigUtils {/*** The bean name of the internally managed Configuration annotation processor.*/public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalConfigurationAnnotationProcessor";/*** The bean name of the internally managed BeanNameGenerator for use when processing* {@link Configuration} classes. Set by {@link AnnotationConfigApplicationContext}* and {@code AnnotationConfigWebApplicationContext} during bootstrap in order to make* any custom name generation strategy available to the underlying* {@link ConfigurationClassPostProcessor}.* @since 3.1.1*/public static final String CONFIGURATION_BEAN_NAME_GENERATOR ="org.springframework.context.annotation.internalConfigurationBeanNameGenerator";/*** The bean name of the internally managed Autowired annotation processor.*/public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalAutowiredAnnotationProcessor";/*** The bean name of the internally managed Required annotation processor.* @deprecated as of 5.1, since no Required processor is registered by default anymore*/@Deprecatedpublic static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalRequiredAnnotationProcessor";/*** The bean name of the internally managed JSR-250 annotation processor.*/public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalCommonAnnotationProcessor";/*** The bean name of the internally managed JPA annotation processor.*/public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME ="org.springframework.context.annotation.internalPersistenceAnnotationProcessor";private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME ="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";/*** The bean name of the internally managed @EventListener annotation processor.*/public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME ="org.springframework.context.event.internalEventListenerProcessor";/*** The bean name of the internally managed EventListenerFactory.*/public static final String EVENT_LISTENER_FACTORY_BEAN_NAME ="org.springframework.context.event.internalEventListenerFactory";/*** Register all relevant annotation post processors in the given registry.* @param registry the registry to operate on* @param source the configuration source element (already extracted)* that this registration was triggered from. May be {@code null}.* @return a Set of BeanDefinitionHolders, containing all bean definitions* that have actually been registered by this call*/public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {// 获取beanFactoryDefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {// //设置依赖比较器beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {// //设置自动装配解析器beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}// 创建BeanDefinitionHolder集合Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);// 注册内部管理的用于处理@configuration注解的后置处理器的beanif (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);// 注册BeanDefinition到注册表中beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册内部管理的用于处理@Autowired,@Value,@Inject以及@Lookup注解的后置处理器beanif (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.// 注册内部管理的用于处理JSR-250注解,例如@Resource,@PostConstruct,@PreDestroy的后置处理器beanif (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.// 注册内部管理的用于处理JPA注解的后置处理器beanif (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}// 注册内部管理的用于处理@EventListener注解的后置处理器的beanif (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}// 注册内部管理用于生产ApplicationListener对象的EventListenerFactory对象if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}
}

截止到这,从xml文件的加载到context 标签 component-scan属性的解析的整体流程已经介绍完成,
接下来看下费尽周折创建的ConfigurationClassPostProcessor中到底有什么?

ConfigurationClassPostProcessor

可以看到ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor和PriorityOrdered。

正好呼应上了上一篇所讲的内容,所以当调用beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class)时。
一定可以获取到Spring已经创建了的ConfigurationClassPostProcessor,并且也一定会调用对应的postProcessBeanDefinitionRegistry();方法。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {//省略部分源码。。。。/*** 定位、加载、解析、注册相关注解** Derive further bean definitions from the configuration classes in the registry.*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {// 根据对应的registry对象生成hashcode值,此对象只会操作一次,如果之前处理过则抛出异常int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}// 将马上要进行处理的registry对象的id值放到已经处理的集合对象中this.registriesPostProcessed.add(registryId);// 处理配置类的bean定义信息processConfigBeanDefinitions(registry);}
}

下一篇帖子介绍ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry()方法都干了些什么。

这篇关于Sping源码(七)—ConfigurationClassPostProcessor创建流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/919260

相关文章

Spring Boot 中的默认异常处理机制及执行流程

《SpringBoot中的默认异常处理机制及执行流程》SpringBoot内置BasicErrorController,自动处理异常并生成HTML/JSON响应,支持自定义错误路径、配置及扩展,如... 目录Spring Boot 异常处理机制详解默认错误页面功能自动异常转换机制错误属性配置选项默认错误处理

Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)

《SpringBoot从main方法到内嵌Tomcat的全过程(自动化流程)》SpringBoot启动始于main方法,创建SpringApplication实例,初始化上下文,准备环境,刷新容器并... 目录1. 入口:main方法2. SpringApplication初始化2.1 构造阶段3. 运行阶

使用Go实现文件复制的完整流程

《使用Go实现文件复制的完整流程》本案例将实现一个实用的文件操作工具:将一个文件的内容完整复制到另一个文件中,这是文件处理中的常见任务,比如配置文件备份、日志迁移、用户上传文件转存等,文中通过代码示例... 目录案例说明涉及China编程知识点示例代码代码解析示例运行练习扩展小结案例说明我们将通过标准库 os

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

python如何创建等差数列

《python如何创建等差数列》:本文主要介绍python如何创建等差数列的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python创建等差数列例题运行代码回车输出结果总结python创建等差数列import numpy as np x=int(in

怎么用idea创建一个SpringBoot项目

《怎么用idea创建一个SpringBoot项目》本文介绍了在IDEA中创建SpringBoot项目的步骤,包括环境准备(JDK1.8+、Maven3.2.5+)、使用SpringInitializr... 目录如何在idea中创建一个SpringBoot项目环境准备1.1打开IDEA,点击New新建一个项