[Spring] @Configuration注解原理

文章目录

      • 1.@Configuration注解介绍
        • 1.1 容器注入ConfigurationClassPostProcessor后置处理器
        • 1.2 ConfigurationClassPostProcessor介绍
      • 2.ConfigurationClassPostProcessor解析
        • 2.1 Parse1
        • 2.2 Parse2
        • 2.3 Parse3
        • 2.4 Parse4
        • 2.5 Parse5
      • 3.ConfigurationClassParser解析
      • 4.ConfigurationClassBeanDefinitionReader解析
        • 4.1@Bean方法解析成BeanDefinition
      • 5.@Configuration总结

1.@Configuration注解介绍

在spring中是通过ConfigurationClassPostProcessor来处理@Configuration注解的。

1.1 容器注入ConfigurationClassPostProcessor后置处理器

  1. 在这里插入图片描述

  2. 在这里插入图片描述

  3. 在这里插入图片描述

  4. 在这里插入图片描述

AnnotationConfigUtils#registerAnnotationConfigProcessors(): 注册注解后置处理器。

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!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 Jakarta Annotations support, and if present add the CommonAnnotationBeanPostProcessor.if (jakartaAnnotationsPresent && !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 JSR-250 support, and if present add an InitDestroyAnnotationBeanPostProcessor// for the javax variant of PostConstruct/PreDestroy.if (jsr250Present && !registry.containsBeanDefinition(JSR250_ANNOTATION_PROCESSOR_BEAN_NAME)) {try {RootBeanDefinition def = new RootBeanDefinition(InitDestroyAnnotationBeanPostProcessor.class);def.getPropertyValues().add("initAnnotationType", classLoader.loadClass("javax.annotation.PostConstruct"));def.getPropertyValues().add("destroyAnnotationType", classLoader.loadClass("javax.annotation.PreDestroy"));def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, JSR250_ANNOTATION_PROCESSOR_BEAN_NAME));}catch (ClassNotFoundException ex) {// Failed to load javax variants of the annotation types -> ignore.}}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (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));}if (!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));}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;}

向容器注入了ConfigurationClassPostProcessor, AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor,EventListenerMethodProcessor, DefaultEventListenerFactory后置处理器。

1.2 ConfigurationClassPostProcessor介绍

在这里插入图片描述

BeanDefinitionRegistryPostProcessor:

在这里插入图片描述

在bean定义文件注册表标准初始化完成后修改内部bean 定义文件.所有的bean定义文件都会被加载,但是bean还没有被实例化.这就允许在下一步的前置处理阶段开始前,继续添加bean的定义文件。

ConfigurationClassPostProcessor 在 refresh#invokeBeanFactoryPostProcessors() 方法中触发方法。

在这里插入图片描述

在这里插入图片描述

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors():

在这里插入图片描述

触发了ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法。

2.ConfigurationClassPostProcessor解析

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry():

在这里插入图片描述

  1. 前面的校验是判断是否处理过该BeanDefinitionRegistry
  2. processConfigBeanDefinitions方法为处理配置类的Bean
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicableconfigCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application contextSingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);if (generator != null) {this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if (this.environment == null) {this.environment = new StandardEnvironment();}// Parse each @Configuration classConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());do {parser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}while (!candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classesif (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {// Clear cache in externally provided MetadataReaderFactory; this is a no-op// for a shared cache since it'll be cleared by the ApplicationContext.((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}}

2.1 Parse1

从当前的Bean 定义文件集合中查找@Configuration修饰的类, 如果没有找到直接返回。

	for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {if (logger.isDebugEnabled()) {logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}

2.2 Parse2

对Configuration类进行排序。

		configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});

2.3 Parse3

检查是否有配置的Bean 名称生成策略。

	    SingletonBeanRegistry sbr = null;if (registry instanceof SingletonBeanRegistry) {sbr = (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);if (generator != null) {this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}

2.4 Parse4

设置环境上下文。

		if (this.environment == null) {this.environment = new StandardEnvironment();}

2.5 Parse5

解析@Configuration配置类。

ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());do {parser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}}while (!candidates.isEmpty());
  1. 解析@Configuration, 根据配置扫描该路径下的@Configuration, @Controller, @Service, @Component等注解。
  2. 通过ConfigurationClassBeanDefinitionReader添加到当前registry中。

3.ConfigurationClassParser解析

通过ConfigurationClassParser 解析每一个@Configuration标记的类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

doProcessConfigurationClass:

	@Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {if (configClass.getMetadata().isAnnotated(Component.class.getName())) {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotationsfor (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.propertySourceRegistry != null) {this.propertySourceRegistry.processPropertySource(propertySource);}else {logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotationsSet<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {for (AnnotationAttributes componentScan : componentScans) {// The config class is annotated with @ComponentScan -> perform the scan immediatelySet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if neededfor (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// Process any @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null;}

解析@Component, @PropertySources, @ComponentScans, @Import, @ImportResource, @Bean注解是否在此类上和其内部。

@ComponentScans为例: 这个parse#doParse(): 通过循环去检查是否符合, 然后封装为scannerBeanDefinition集合。通过遍历集合得到BeanDefinitionHolder中的beanDefinition, 然后解析其中的内容。

在这里插入图片描述

parse -> doScan方法, 通过ClassPathBeanDefinitionScanner扫描帮助解析类的内容。

在这里插入图片描述

在这里插入图片描述

4.ConfigurationClassBeanDefinitionReader解析

通过ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()方法将上面通过ConfigurationClassParser解析得到的BeanDefinition集合读取和注册进register。

在这里插入图片描述

在这里插入图片描述

	private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName = configClass.getBeanName();if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}

将一个ConfigurationClass和它内部所有被@Bean标记的方法, 变成BeanDefinition, 注册进register。

  1. 如果当前类是通过@Import被别的配置类引入,则将当前类转化成bean definition注册.
  2. 将当前类的所有被@Bean标记方法,转化为bean definition注册到当前registry
  3. 解析当前类上@ImportResource
  4. 解析当前类引入的ImportBeanDefinitionRegistrar接口的子类.

在这里插入图片描述

4.1@Bean方法解析成BeanDefinition

在这里插入图片描述

/*** Read the given {@link BeanMethod}, registering bean definitions* with the BeanDefinitionRegistry based on its contents.*/private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {ConfigurationClass configClass = beanMethod.getConfigurationClass();MethodMetadata metadata = beanMethod.getMetadata();String methodName = metadata.getMethodName();// Do we need to mark the bean as skipped by its condition?if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {configClass.skippedBeanMethods.add(methodName);return;}if (configClass.skippedBeanMethods.contains(methodName)) {return;}AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);Assert.state(bean != null, "No @Bean annotation attributes");// Consider name and any aliasesList<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));String beanName = (!names.isEmpty() ? names.remove(0) : methodName);// Register aliases even when overriddenfor (String alias : names) {this.registry.registerAlias(beanName, alias);}// Has this effectively been overridden before (e.g. via XML)?if (isOverriddenByExistingDefinition(beanMethod, beanName)) {if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +"' clashes with bean name for containing configuration class; please make those names unique!");}return;}ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);beanDef.setResource(configClass.getResource());beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));if (metadata.isStatic()) {// static @Bean methodbeanDef.setBeanClassName(configClass.getMetadata().getClassName());beanDef.setFactoryMethodName(methodName);}else {// instance @Bean methodbeanDef.setFactoryBeanName(configClass.getBeanName());beanDef.setUniqueFactoryMethodName(methodName);}beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);Autowire autowire = bean.getEnum("autowire");if (autowire.isAutowire()) {beanDef.setAutowireMode(autowire.value());}String initMethodName = bean.getString("initMethod");if (StringUtils.hasText(initMethodName)) {beanDef.setInitMethodName(initMethodName);}String destroyMethodName = bean.getString("destroyMethod");beanDef.setDestroyMethodName(destroyMethodName);// Consider scopingScopedProxyMode proxyMode = ScopedProxyMode.NO;AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);if (attributes != null) {beanDef.setScope(attributes.getString("value"));proxyMode = attributes.getEnum("proxyMode");if (proxyMode == ScopedProxyMode.DEFAULT) {proxyMode = ScopedProxyMode.NO;}}// Replace the original bean definition with the target one, if necessaryBeanDefinition beanDefToRegister = beanDef;if (proxyMode != ScopedProxyMode.NO) {BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(new BeanDefinitionHolder(beanDef, beanName), this.registry,proxyMode == ScopedProxyMode.TARGET_CLASS);beanDefToRegister = new ConfigurationClassBeanDefinition((RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);}if (logger.isDebugEnabled()) {logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",configClass.getMetadata().getClassName(), beanName));}this.registry.registerBeanDefinition(beanName, beanDefToRegister);}

该方法是生成一个ConfigurationClassBeanDefinition, 并将其注册到registry。

  1. 设置Bean定义来源
  2. 设置工厂名称/工厂方法
  3. 设置Autowire方式
  4. 设置initMethod/destoryMethod
  5. 设置scope

一个@Configuration类的@Bean会作为一个工厂bean的方式添加到registry中, 实例化Bean时候, 会调用工厂对应的方法。

5.@Configuration总结

ConfigurationClassPostProcessor- > ConfigurationClassParser / ConfigurationClassPostProcessorReader -> 解析@Bean等注解。

  1. 注册时机: AnnotationConfigApplicationContext#this#AnnotatedBeanDefinitionReader#this -> AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)

  2. 执行时机: AbstractApplicationContext#refresh()#invokeBeanFactoryPostProcessors(beanFactory)
    生成对应的BeanDefinition注册到当前BeanDefinitionRegistry中。

  3. 解析内容
    1. @Bean方法
    2. @Import注解,引入的其他@Configuration类或ImportBeanDefinitionRegistrar子类
    3. @ImportResource注解

  4. 当前@Configuration标记的类也会作为一个bean添加到BeanDefinitionRegistry

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

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

相关文章

Spring系列文章:Spring6集成MyBatis3.5

1、引入依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.2</version></dependency><dependency><groupId>org.mybatis</groupId><artif…

SAP中的新旧事务码

SAP中的新旧事务码 SAP随着新版本的发布&#xff0c;我们知道sap已经更新了很多的程序和TCODE。sap提供了很多新的TCODE来替换旧的TCODE&#xff0c;新TCODE有很多的新特性和新功能。在这个这种情况下&#xff0c;很多旧TCODE就会被废弃。我们如何查找这个替换呢&#xff1f; …

KMP算法

个人理解 我理解的KMP 算法就是记录前缀与后缀&#xff0c;每当遇到不匹配的时候由于后缀已经被匹配过&#xff0c;所以下次应该跳到匹配过的后缀也就是相应的前缀后面在进行匹配。 如何计算前缀 参考卡哥网站 前缀计算 然后利用前缀表去做匹配 leetcode 28 class Solutio…

【Kubernetes理论篇】2023年最新CKA考题+解析

文章目录 第一题&#xff1a;RBAC授权访问控制第二题&#xff1a;Node节点维护第三题&#xff1a;K8S集群版本升级第四题&#xff1a;ETCD数据库备份恢复第五题&#xff1a;NetworkPolicy网络策略第六题&#xff1a;Service四层负载第七题&#xff1a;Ingress七层负载第八题&am…

nodejs采集淘宝、天猫网商品详情数据以及解决_m_h5_tk令牌及sign签名验证(2023-09-09)

一、淘宝、天猫sign加密算法 淘宝、天猫对于h5的访问采用了和APP客户端不同的方式&#xff0c;由于在h5的js代码中保存appsercret具有较高的风险&#xff0c;mtop采用了随机分配令牌的方式&#xff0c;为每个访问端分配一个token&#xff0c;保存在用户的cookie中&#xff0c;通…

OpenCV 11(图像金字塔)

一、 图像金字塔 **图像金字塔**是图像中多尺度表达的一种&#xff0c;最主要用于图像的分割&#xff0c;是一种以多分辨率来解释图像的有效但概念简单的结构。简单来说, 图像金字塔是同一图像不同分辨率的子图集合. 图像金字塔最初用于机器视觉和图像压缩。其通过梯次向下采…

【面试心得】WebBench 整理

在面试九识的时候&#xff0c;被问到了WebBench的原理&#xff0c;当时没答上来&#xff0c;这里做一个整理 WebBench 源码【带注释】&#xff1a;GitHub - YukunJ/annotated-webbench-1.5: bilingually annotated Webbench-1.5 webbench是一个轻量的压测工具&#xff0c;可以…

docker desktop如何一键进入容器内部

对着对应的容器 点击 view files

交友盲盒完整版——详细源码分享

现在目前比较火热的一款app交友盲盒是通过uniappspringboot技术来制作的&#xff0c;原理其实很简单&#xff0c;大家一看便知。 大家自行下载到手机里面去使用即可&#xff0c;不支持ios手机 演示地址&#xff1a;https://share.weiyun.com/l3ovztce 下面就是给大家分享源码了…

快速文件复制与删除工具,将复制时文件夹里的原文件删除掉

无论是工作还是生活&#xff0c;我们都离不开文件的复制和管理。然而&#xff0c;手动复制文件不仅费时费力&#xff0c;而且容易出错。现在&#xff0c;我们为您推荐一款快速文件复制与删除工具&#xff0c;让您的文件管理更加高效&#xff01; 首先&#xff0c;我们要进入文…

由于电脑出现msvcr110.dll提示错误的解决方法

最近&#xff0c;我在尝试运行一款新的软件时&#xff0c;突然遇到了一个错误提示&#xff0c;提示说缺少msvcr110.dll文件&#xff0c;导致软件无法启动。在使用电脑过程中&#xff0c;我们常常会遇到一些系统文件丢失的问题。其中&#xff0c;msvcr110.dll是Windows操作系统中…

Layui快速入门之第二节布局容器(固定宽度与完整宽度)

目录 一&#xff1a;固定宽度 二&#xff1a; 完整宽度 一&#xff1a;固定宽度 将栅格放入一个带有 class"layui-container" 的特定容器中&#xff0c;以便在小屏幕以上的设备中固定宽度&#xff0c;让列可控(两侧有留白效果) <!--固定宽度(两侧有留白效果)--&…

el-dialog弹窗中进度条的(mqtt提供)数据无法清空(清空方法)

清空方法 this.$nextTick(()>{this.$refs.devicefromDialog.clearValidate(airSwitchNo);//清除的校验规则prop传的值this.$refs[devicefromDialog].resetFields();//清除表单内容}) 场景&#xff1a;进度条的数据需要在关闭的时候&#xff0c;清空上一次的缓存记录&#xf…

Java开发之Redis核心内容【面试篇 完结版】

文章目录 前言一、redis使用场景1. 知识分布2. 缓存穿透① 问题引入② 举例说明③ 解决方案④ 实战面试 3. 缓存击穿① 问题引入② 举例说明③ 解决方案④ 实战面试 4. 缓存雪崩① 问题引入② 举例说明③ 解决方案④ 实战面试 5. 缓存-双写一致性① 问题引入② 举例说明③ 解决…

动态规划之子数组系列

子数组系列 1. 环形⼦数组的最⼤和2. 乘积最大子数组3. 等差数列划分4. 最长湍流子数组5. 单词拆分6. 环绕字符串中唯⼀的子字符串 1. 环形⼦数组的最⼤和 1.题目链接&#xff1a;环形⼦数组的最⼤和 2.题目描述&#xff1a;给定一个长度为 n 的环形整数数组 nums &#xff0c…

(其他) 剑指 Offer 67. 把字符串转换成整数 ——【Leetcode每日一题】

❓ 剑指 Offer 67. 把字符串转换成整数 难度&#xff1a;中等 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。 首先&#xff0c;该函数会根据需要丢弃无用的开头空格字符&#xff0c;直到寻找到第一个非空格的字符为…

STM32初学-外部RTC时钟芯片DS3231

RTC(Real_Time Clock)即实时时钟&#xff0c;它是电子产品中不可或缺的东西。其最直接的作用就是时钟功能。细心的朋友可以发现&#xff0c;当我们的电脑或者手机没联网时&#xff0c;仍然可以正常显示日期与时钟&#xff0c;这就是RTC的功劳。 RTC的运行无需网络连接&#xff…

JavaScript设计模式(三)——单例模式、装饰器模式、适配器模式

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

MySQL——日志

日志的作用 1.用来排错 2.用来做数据分析 3.了解程序的运行情况&#xff0c;是否健康--》了解MySQL的性能&#xff0c;运行情况 分类 mysql很多有类型的日志&#xff0c;按照组件划分的话&#xff0c;可以分为 服务层日志 和 存储引擎层日志 &#xff1a; - 服务层…

java包装类简单认识泛型

1 包装类 在 Java 中&#xff0c;由于基本类型不是继承自 Object &#xff0c;为了在泛型代码中可以支持基本类型&#xff0c; Java 给每个基本类型都对应了一个包装 类型。类中比如由属性/方法 使用比较方便 1.1 基本数据类型和对应的包装类 1.2 装箱和拆箱 装包/装箱 : …