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

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”