建设委员会的网站/热搜关键词
文章目录
- 一、源码时序图
- 二、源码解析
- 1. 运行案例程序启动类
- 2. 解析AnnotationConfigApplicationContext类的AnnotationConfigApplicationContext(Class<?>... componentClasses)构造方法
- 3. 解析AbstractApplicationContext类的refresh()方法
- 4. 解析AbstractApplicationContext类的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)方法
- 5. 解析PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)方法
- 6. 解析PostProcessorRegistrationDelegate类的invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup)方法
- 7. 解析ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法
- 8. 解析ConfigurationClassPostProcessor类的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法
- 9. 解析ConfigurationClassParser类的parse(SetconfigCandidates)方法
- 10. 解析ConfigurationClassParser类的parse(AnnotationMetadata metadata, String beanName)方法
- 11. 解析ConfigurationClassParser类的processConfigurationClass(ConfigurationClass configClass, Predicatefilter)方法
- 12. 解析ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法
- 13. 解析ConfigurationClassParser类的retrieveBeanMethodMetadata(SourceClass sourceClass)方法
- 14. 回到ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法。
- 15. 回到ConfigurationClassPostProcessor类的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法
- 16. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitions(SetconfigurationModel)方法
- 17. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)方法
- 18. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)方法
- 19. 解析DefaultListableBeanFactory类的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法
一、源码时序图
本节,就以源码时序图的方式,直观的感受下@Bean注解在Spring源码层面的执行流程。@Bean注解在Spring源码层面的执行流程如图所示:
由图可以看出,@Bean注解在Spring源码层面的执行流程会涉及到BeanTest类、AnnotationConfigApplicationContext类、AbstractApplicationContext类、PostProcessorRegistrationDelegate类、ConfigurationClassPostProcessor类、ConfigurationClassParser类、ConfigurationClassBeanDefinitionReader类和DefaultListableBeanFactory类。具体的源码执行细节参见源码解析部分。
二、源码解析
@Bean注解在Spring源码层面的执行流程,结合源码执行的时序图,会理解的更加深刻。
1. 运行案例程序启动类
在BeanTest类的main()方法中调用了AnnotationConfigApplicationContext类的构造方法,并传入了ComponentScanConfig类的Class对象来创建IOC容器。接下来,会进入AnnotationConfigApplicationContext类的构造方法。
2. 解析AnnotationConfigApplicationContext类的AnnotationConfigApplicationContext(Class<?>… componentClasses)构造方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();
}
可以看到,在上述构造方法中,调用了refresh()方法来刷新IOC容器。
3. 解析AbstractApplicationContext类的refresh()方法
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {//############省略其他代码##############try {//############省略其他代码##############invokeBeanFactoryPostProcessors(beanFactory);//############省略其他代码##############}catch (BeansException ex) {//############省略其他代码##############}finally {//############省略其他代码##############}}
}
refresh()方法是Spring中一个非常重要的方法,很多重要的功能和特性都是通过refresh()方法进行注入的。可以看到,在refresh()方法中,调用了invokeBeanFactoryPostProcessors()方法。
4. 解析AbstractApplicationContext类的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)方法
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));}
}
可以看到,在AbstractApplicationContext类的invokeBeanFactoryPostProcessors()方法中调用了PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors()方法。
5. 解析PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)方法
由于方法的源码比较长,这里,只关注当前最核心的逻辑,如下所示:
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {//############省略其他代码##############List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.String[] postProcessorNames =beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.boolean reiterate = true;while (reiterate) {reiterate = false;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);for (String ppName : postProcessorNames) {if (!processedBeans.contains(ppName)) {currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);reiterate = true;}}sortPostProcessors(currentRegistryProcessors, beanFactory);registryProcessors.addAll(currentRegistryProcessors);invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());currentRegistryProcessors.clear();}//############省略其他代码##############
}
可以看到,在PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, ListbeanFactoryPostProcessors)方法中,BeanDefinitionRegistryPostProcessor的实现类在执行逻辑上会有先后顺序,并且最终都会调用invokeBeanDefinitionRegistryPostProcessors()方法。
6. 解析PostProcessorRegistrationDelegate类的invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup)方法
private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process").tag("postProcessor", postProcessor::toString);postProcessor.postProcessBeanDefinitionRegistry(registry);postProcessBeanDefRegistry.end();}
}
可以看到,在invokeBeanDefinitionRegistryPostProcessors()方法中,会循环遍历postProcessors集合中的每个元素,调用postProcessBeanDefinitionRegistry()方法注册Bean的定义信息。
7. 解析ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {//##########省略其他代码###################processConfigBeanDefinitions(registry);
}
可以看到,在postProcessBeanDefinitionRegistry()方法中,会调用processConfigBeanDefinitions()方法。
8. 解析ConfigurationClassPostProcessor类的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法
这里,重点关注方法中的如下逻辑:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//############省略其他代码#################// 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 {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");parser.parse(candidates);parser.validate();//############省略其他代码#################this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();//############省略其他代码#################}while (!candidates.isEmpty());//############省略其他代码#################
}
可以看到,在processConfigBeanDefinitions()方法中,创建了一个ConfigurationClassParser类型的对象parser,并且调用了parser的parse()方法来解析类的配置信息。
9. 解析ConfigurationClassParser类的parse(SetconfigCandidates)方法
public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}this.deferredImportSelectorHandler.process();
}
可以看到,在ConfigurationClassParser类的parse(SetconfigCandidates)方法中,调用了类中的另一个parse()方法。
10. 解析ConfigurationClassParser类的parse(AnnotationMetadata metadata, String beanName)方法
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
可以看到,上述parse()方法的实现比较简单,直接调用了processConfigurationClass()方法。
11. 解析ConfigurationClassParser类的processConfigurationClass(ConfigurationClass configClass, Predicatefilter)方法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {//###############省略其他代码####################SourceClass sourceClass = asSourceClass(configClass, filter);do {sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);}while (sourceClass != null);this.configurationClasses.put(configClass, configClass);
}
可以看到,在processConfigurationClass()方法中,会通过do-while()循环获取配置类和其父类的注解信息,SourceClass类中会封装配置类上注解的详细信息。在在processConfigurationClass()方法中,调用了doProcessConfigurationClass()方法。
12. 解析ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {//##################省略其他代码##################// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}//##################省略其他代码##################// No superclass -> processing is completereturn null;
}
这里,只关注与@Bean注解相关的方法,可以看到,在doProcessConfigurationClass()方法中调用了retrieveBeanMethodMetadata()方法来解析sourceClass中有关@Bean注解的属性信息。
13. 解析ConfigurationClassParser类的retrieveBeanMethodMetadata(SourceClass sourceClass)方法
private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {AnnotationMetadata original = sourceClass.getMetadata();Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {try {AnnotationMetadata asm = this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());if (asmMethods.size() >= beanMethods.size()) {Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());for (MethodMetadata asmMethod : asmMethods) {for (MethodMetadata beanMethod : beanMethods) {if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {selectedMethods.add(beanMethod);break;}}}if (selectedMethods.size() == beanMethods.size()) {beanMethods = selectedMethods;}}}catch (IOException ex) {logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);}}return beanMethods;
}
可以看到,在retrieveBeanMethodMetadata()方法中主要是解析@Bean注解,并且将解析到的方法元数据存入 Set集合中并返回。
14. 回到ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法。
这里,还是重点看下方法中与@Bean注解有关的代码片段,如下所示:
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
调用retrieveBeanMethodMetadata()方法获取到标注了@Bean注解的方法的元数据集合后,遍历方法的元数据集合,将方法的元数据methodMetadata和配置类configClass传入BeanMethod类的构造方法,创建BeanMethod对象,并调用configClass的addBeanMethod()方法传入创建的BeanMethod对象。
configClass的addBeanMethod()方法的源码详见:org.springframework.context.annotation.ConfigurationClass#addBeanMethod(BeanMethod method),如下所示:
void addBeanMethod(BeanMethod method) {this.beanMethods.add(method);
}
可以看到,在addBeanMethod()方法中,调用了beanMethods的add()方法添加BeanMethod对象。
beanMethods的源码详见:org.springframework.context.annotation.ConfigurationClass#beanMethods,如下所示:
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
可以看到,beanMethods是一个LinkedHashSet类型的集合。也就是说,在ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicatefilter)方法中,会将解析出的标注了@Bean注解的元数据封装成BeanMethod对象,添加到一个LinkedHashSet类型的beanMethods集合中。
15. 回到ConfigurationClassPostProcessor类的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法
此时,重点关注下如下源码片段:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {//############省略其他代码#################do {//############省略其他代码#################this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();//############省略其他代码#################}while (!candidates.isEmpty());//############省略其他代码#################
}
可以看到,在processConfigBeanDefinitions()方法的do-while()循环中,调用了reader的loadBeanDefinitions()方法来加载Bean的定义信息。
16. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitions(SetconfigurationModel)方法
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}
}
可以看到,在loadBeanDefinitions()方法中,会循环遍历,传入的configurationModel集合,并调用loadBeanDefinitionsForConfigurationClass()方法处理遍历的每个元素。
17. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)方法
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {//###############省略其他代码################for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}//###############省略其他代码################
}
可以看到,在loadBeanDefinitionsForConfigurationClass()方法中,会循环遍历通过configClass获取到的BeanMethod集合,并调用loadBeanDefinitionsForBeanMethod()方法处理遍历的每个BeanMethod对象。
18. 解析ConfigurationClassBeanDefinitionReader类的loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)方法
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {ConfigurationClass configClass = beanMethod.getConfigurationClass();MethodMetadata metadata = beanMethod.getMetadata();String methodName = metadata.getMethodName();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");List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));String beanName = (!names.isEmpty() ? names.remove(0) : methodName);for (String alias : names) {this.registry.registerAlias(beanName, alias);}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, beanName);beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));if (metadata.isStatic()) {// static @Bean methodif (configClass.getMetadata() instanceof StandardAnnotationMetadata sam) {beanDef.setBeanClass(sam.getIntrospectedClass());}else {beanDef.setBeanClassName(configClass.getMetadata().getClassName());}beanDef.setUniqueFactoryMethodName(methodName);}else {// instance @Bean methodbeanDef.setFactoryBeanName(configClass.getBeanName());beanDef.setUniqueFactoryMethodName(methodName);}if (metadata instanceof StandardMethodMetadata sam) {beanDef.setResolvedFactoryMethod(sam.getIntrospectedMethod());}beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);boolean autowireCandidate = bean.getBoolean("autowireCandidate");if (!autowireCandidate) {beanDef.setAutowireCandidate(false);}String initMethodName = bean.getString("initMethod");if (StringUtils.hasText(initMethodName)) {beanDef.setInitMethodName(initMethodName);}String destroyMethodName = bean.getString("destroyMethod");beanDef.setDestroyMethodName(destroyMethodName);ScopedProxyMode 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;}}BeanDefinition 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, beanName);}if (logger.isTraceEnabled()) {logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",configClass.getMetadata().getClassName(), beanName));}this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
可以看到,在loadBeanDefinitionsForBeanMethod()方法中解析了@Bean注解中的属性信息,并将解析出的信息封装到一个BeanDefinition对象中,最终会调用registry对象的registerBeanDefinition()方法将封装的BeanDefinition对象注册到IOC容器中。
19. 解析DefaultListableBeanFactory类的registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {//##############省略其他代码#################BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {//##############省略其他代码#################this.beanDefinitionMap.put(beanName, beanDefinition);}else {//##############省略其他代码#################if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;removeManualSingletonName(beanName);}}else {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);}else if (isConfigurationFrozen()) {clearByTypeCache();}
}
可以看到,Spring会解析这些标注了@Bean注解的方法,将解析出的信息封装成BeanDefinition对象注册到beanDefinitionMap中。这一点和第1章中,注册ConfigurationClassPostProcessor类的Bean定义信息有点类似。
好了,至此,@Bean注解在Spring源码中的执行流程分析完毕。
相关文章:

深入分析@Bean源码
文章目录一、源码时序图二、源码解析1. 运行案例程序启动类2. 解析AnnotationConfigApplicationContext类的AnnotationConfigApplicationContext(Class<?>... componentClasses)构造方法3. 解析AbstractApplicationContext类的refresh()方法4. 解析AbstractApplicationC…...

Web Components学习(1)
一、什么是web components 开发项目的时候为什么不手写原生 JS,而是要用现如今非常流行的前端框架,原因有很多,例如: 良好的生态数据驱动试图模块化组件化等 Web Components 就是为了解决“组件化”而诞生的,它是浏…...

Element-UI实现复杂table表格结构
Element-UI组件el-table用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。将使用到以下两项,来完成今天demo演示:多级表头:数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。合…...

Azure AD 与 AWS 单一帐户SSO访问集成,超详细讲解,包括解决可能出现的错误问题
本教程介绍如何将 AWS Single-Account Access 与 Azure Active Directory (Azure AD) 相集成。 将 AWS Single-Account Access 与 Azure AD 集成后,可以: 在 Azure AD 中控制谁有权访问 AWS Single-Account Access。让用户使用其 Azure AD 帐户自动登录…...

lvgl 笔记 按钮部件 (lv_btn) 和 开关部件 (lv_switch)
按钮基础使用方法: lv_btn 和 lb_obj 使用方法一样,只是外表并不相同,基础创建方法只需一行代码。 lv_obj_t* btn lv_btn_create(lv_scr_act()); 添加大小和位置: lv_obj_t* btn lv_btn_create(lv_scr_act()); lv_obj_set_s…...

Python高频面试题——生成器(最通俗的讲解)
生成器定义在 Python 中,使用了 yield 的函数被称为生成器(generator)。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。 在调用生成器运行的过程中…...

品牌软文怎么写?教你几招
软文是什么?软文的本质就是广告,当然不是明晃晃的推销,而是自然隐晦地植入产品信息,引导更多用户自愿下单。 品牌软文对于写手的经验、内容的质量要求都相对较高,否则写出来的软文无法达到预期的效果。品牌软文怎么写…...

Kubernetes (k8s) 污点(Taint)介绍、示例
Kubernetes (k8s) 污点(Taint) 是一种机制,用于标记一个节点(Node)不可被调度的状态。它可以将一个污点标记添加到节点上,以防止 Pod 被调度到该节点上。污点可以用于实现各种策略,例如分离故障…...

Docker学习(二十一)构建 java 项目基础镜像
目录1.下载 JDK 包2.编写 Dockerfile3.构建镜像4.创建容器测试1.下载 JDK 包 JDK各版本官网下载地址: https://www.oracle.com/java/technologies/downloads/archive/#JavaSE 这里我们以 JDK 8u351 为例,点击 Java SE (8U211 and later)。 点击下载 jd…...

python中的上下文原理
目录with语句上下文管理器原理自定义上下文管理器contextmanager 装饰器with语句 在我们日常使用场景中,经常会操作一些资源,比如文件对象、数据库连接、Socket连接等,资源操作完了之后,不管操作的成功与否,最重要的事…...

可复用测试用例描述要素
测试用例的输入、操作、预期结果和评估标准、前提条件是测试用例不可少的要素,但对于可复用测试用例而言,这是不够的。本文在文献规定的测试用例要素基础上,增加了新的内容。从而从多个角度完整地对可复用测试用例进行了描述,为可…...

lnmp中遇到open_basedir配置无效问题
在使用LNMP包安装PHP时,发现直接修改php.ini的配置是无法生效的,其原因竟然是因为nginx的配置文件,覆盖了php.ini的配置。 解决: 1、找到nginx的open_basedir配置文件:(下面是我的文件地址) …...

SpringBoot【知识加油站】---- REST开发
SpringBoot【知识加油站】---- REST开发1. REST 简介2. REST 风格3. RESTful 入门案例1. REST 简介 REST:Representaional State Transfer,表现形式状态转换 传统风格资源描述形式 http://localhost/user/getById?id1 http://localhost/user/saveUser…...

三 Go的语言容器
1. 数组 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,所以在Go语言中很少直接使用数组 声明语法: var 数组变量名 [元素数量]Typepackage main import ("fmt" ) fu…...

2023年全国最新会计专业技术资格精选真题及答案16
百分百题库提供会计专业技术资格考试试题、会计考试预测题、会计专业技术资格考试真题、会计证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 一、单选题 1.下列各项关于会计监督职能的表述中,正确的是ÿ…...

模板进阶(仿函数,特化等介绍)
非类型模板参数 模板参数有类型形参和非类型形参; 类型形参:使用typename或者class修饰的参数类型名称 非类型形参:一个普通常量作为模板参数形参,不能为浮点数,字符类型以及类对象; #include<iostrea…...

Beats:在 Docker 中同时部署 Metricbeat 和 Elasticsearch
在本教程中,我们将部署一个 metricbeat 来监控正在运行的容器的健康状况和系统指标。 为什么需要监控,为什么需要 Metricbeat? 一个常见的问题,但很少有人回答。 首先,无论我们部署的是 docker 容器还是老式的金属箱&…...

编码技巧——Redis Pipeline
本文介绍Redis pipeline相关的知识点及代码示例,包括Redis客户端-服务端的一次完整的网络请求、pipeline与client执行多命令的区别、pipeline与Redis"事务"、pipeline的使用代码示例; pipeline与client执行多命令的区别 Redis是一种基于客户…...

ArcGIS制图技巧:制图入门与点、线、面状符号制作
目的: 1、了解地图制作目的; 2、了解在ArcMap平台中制作地图大致过程。 3、掌握地形图生成的操作; 4、掌握地形图的正确输出方法。 5、理解点状符号、线状符号、面状符号的基本概念; 6、理解地形点状符号、线状符号、面状符…...

Java基础 关于字典数据维护接口设计
开发环境 Eclipse2022JDK1.8 目录 1. 概述 2. 实现步骤 2.1 定义通用接口 2.2 定义实体类 2.3 接口扩展 2.4 接口实现 2.5 功能测试 3. 结语 1. 概述 每一个信息系统或多或少都带有一些数据字典,在维护上,基本上分为增删改查,也就是对数据…...

从零开始学架构——复杂度来源
复杂度来源——高性能 对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机,从电子管计算机到晶体管计算机再到集成电路计算机,运算性能从每秒几次提升到每秒几亿次。但伴随性能越来越高,相应的方法和系统复杂度也是越来越高。现代的计算机CPU集成…...

什么时候需要分表分库?
在当今互联网时代,海量数据基本上是每一个成熟产品的共性,特别是在移动互联网产品中,几乎每天都在产生数据,例如,商城的订单表、支付系统的交易明细以及游戏中的战报等等。对于一个日活用户在百万数量级的商城来说&…...

冰刃杀毒工具使用实验(29)
实验目的 (1)学习冰刃的基本功能; (2)掌握冰刃的基本使用方法;预备知识 windows操作系统的基本知识,例如:进程、网络、服务和文件等的了解。 冰刃是一款广受好评的ARK工…...

聊聊图像分割的DICE和IOU指标
目录 1. 介绍 2. dice 和 iou 的联系 3. 代码实现 3.1 dice 3.2 iou 3.3 test 3.4 dice 和 iou 的关系曲线 4. 代码 1. 介绍 dice 和 iou 都是衡量两个集合之间相似性的度量 dice计算公式: iou计算公式: iou的集合理解: iou 其实就…...

软件设计师教程(十)计算机系统知识-结构化开发
软件设计师教程 软件设计师教程(一)计算机系统知识-计算机系统基础知识 软件设计师教程(二)计算机系统知识-计算机体系结构 软件设计师教程(三)计算机系统知识-计算机体系结构 软件设计师教程(…...

链表OJ之 快慢指针法总结
欢迎来到 Claffic 的博客 💞💞💞 前言: 快慢指针指的是每次指针移动的步长,是解决链表相关的题目的一大利器,下面我将以例题的形式讲解快慢指针法。 目录 一. 链表的中间结点 思路: 代码实…...

C++STL详解(五)——list的介绍与使用
文章目录list的介绍list的使用list的定义方法list迭代器失效问题list插入和删除inserteraselist迭代器的使用begin,end 和 rbegin,rendlist元素访问front 和 backlist容量控制与数据清理resizeclearlist操作函数spliceremove 和 remove_ifuniquemergerev…...

进程和进程的调度
今天,为大家带来进程和进程的调度的学习 1.认识计算机 2.什么是操作系统 3.什么是进程 4.进程管理 5.进程的属性 6.进程的调度 7.进程调度的过程 8.内存分配 1.认识计算机 计算机的组成有五大部分 1.CPU(是计算机的大脑,负责逻辑运算和控制) 2.内存 3.外存 4.输入…...

TypeScript 深度剖析:TypeScript 的理解?与 JavaScript 的区别?
一、是什么 TypeScript 是 JavaScript 的类型的超集,支持ES6语法,支持面向对象编程的概念,如类、接口、继承、泛型等 超集,不得不说另外一个概念,子集,怎么理解这两个呢,举个例子,如…...

美颜SDK关键技术讲解——人脸识别与人脸美化
拍摄,自从智能手机普及之后就已经不再是小众爱好,使用手机拍摄记录生活几乎成了人们的日常。在巨量的需求下,美颜工具、美颜SDK已经被广泛应用于各大视频拍摄平台。虽然经常听到美颜SDK,但是大多数人并不了解它,下文小…...