0


Spring的@Bean注解原理详解

一. @Bean注解的作用

这是一个我们很常用的注解,作用是指示一个方法生成一个由Spring管理的Bean。

之前的文章都是使用的xml或者自定义形式的项目研究的,本篇是讲注解的,所以直接使用最简单的SpringBoot项目了,版本号:2.3.12.RELEASE
在这里插入图片描述
在这里插入图片描述
本篇就已这个例子进行分析

@Bean

注解的实现方式

二. 先了解BeanFactoryPostProcessor

BeanFactoryPostProcessor

BeanPostProcessor

是不是一样的,关于BeanPostProcessor可以看这篇:Spring的BeanPostProcessor分析,千万别把两个搞混了。

BeanFactoryPostProcessor源码:

@FunctionalInterfacepublicinterfaceBeanFactoryPostProcessor{/**
     * 在标准初始化之后修改应用程序上下文的内部 bean 工厂。所有 bean 定义都将被加载,但还没有 bean 被实例化。
     * 这允许覆盖或添加属性,甚至是急切初始化的 bean。
     */voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException;}

Spring IoC容器允许BeanFactoryPostProcessor在容器实例化任何bean之前读取bean的定义(配置元数据),并可以修改它或者实现bean动态代理等。同时可以定义多个BeanFactoryPostProcessor,通过设置’order’属性来确定各个BeanFactoryPostProcessor执行顺序。

与BeanFactoryPostProcessor相关的两个很重要的类:

  • BeanDefinitionRegistryPostProcessor 这个接口是对BeanFactoryPostProcessor的进一步扩展,其中的postProcessBeanDefinitionRegistry方法可以对BeanDefinition做更多的定义
  • ConfigurationClassPostProcessor 这个类实现了BeanDefinitionRegistryPostProcessor,具体的实现了对Bean的扫描和BeanDefinition的修改

三. 源码分析

@Bean注解是在的

org.springframework.context.support.AbstractApplicationContext#refresh

方法中被加载的,具体是在

org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors

方法中被扫描到的,关于

refresh

方法就不再做过多描述了,不了解的同学可以看Spring栏目里面的文章进行了解。
首先来看

refresh

方法中的

invokeBeanFactoryPostProcessors

这一步:

// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);

这个方法主要作用就是根据反射机制从BeanDefinitionRegistry(bean定义注册中心)中找到所有实现了BeanFactoryPostProcessor接口bean,并调用其postProcessBeanFactory()接口方法, 其实就是对Bean定义的增强/修改,同时也是一个非常有效的扩展点。跟进这个方法:

publicstaticvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,List<BeanFactoryPostProcessor> beanFactoryPostProcessors){//一开始进来的时候,beanFactoryPostProcessors中有三个BeanFactoryPostProcessor的实现,这三个与本篇关系不大就不详细说了,感兴趣的同学可以自行断点查看// Invoke BeanDefinitionRegistryPostProcessors first, if any.// 如果有的话,首先执行 BeanDefinitionRegistryPostProcessorsSet<String> processedBeans =newHashSet<>();if(beanFactory instanceofBeanDefinitionRegistry){BeanDefinitionRegistry registry =(BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors =newArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors =newArrayList<>();for(BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors){//如果入参的BeanFactoryPostProcessor 中有实现自BeanDefinitionRegistryPostProcessor的// 那就先执行它的postProcessBeanDefinitionRegistry  然后对beanFactoryPostProcessors中的进行分组if(postProcessor instanceofBeanDefinitionRegistryPostProcessor){BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;//
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);}else{
                regularPostProcessors.add(postProcessor);}}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// Separate between BeanDefinitionRegistryPostProcessors that implement// PriorityOrdered, Ordered, and the rest.List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors =newArrayList<>();// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.// 首先,调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessor// 这里是从beanFactory中查找BeanDefinitionRegistryPostProcessor的Bean// 这里获取的结果是:org.springframework.context.annotation.internalConfigurationAnnotationProcessor   能获取到这个的原因在下面写// 对应的类是:org.springframework.context.annotation.ConfigurationClassPostProcessor  这个类也就是本篇的重点类String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class,true,false);for(String ppName : postProcessorNames){if(beanFactory.isTypeMatch(ppName,PriorityOrdered.class)){// ConfigurationClassPostProcessor实现了PriorityOrdered  所以优先处理  此处先实例化然后用于后续执行
                currentRegistryProcessors.add(beanFactory.getBean(ppName,BeanDefinitionRegistryPostProcessor.class));// 记录已实例化的  其实就是记录一下已经处理过的  后续需要排除
                processedBeans.add(ppName);}}sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);// 然后进入这个方法处理  这一步就是具体的ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry执行逻辑了// 下面会详细分析  这里打个标记!!!!!!  方便搜索invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.// 接下来,调用实现 Ordered 的 BeanDefinitionRegistryPostProcessors
        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);
        currentRegistryProcessors.clear();// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.// 最后,循环调用所有其他BeanDefinitionRegistryPostProcessors直到没有未处理的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);
            currentRegistryProcessors.clear();}// 到这里 我们可以看到BeanDefinitionRegistryPostProcessor处理流程是先处理PriorityOrdered的// 再处理Ordered的, 最后在循环处理所有的// 目的是先执行内置必要的BeanDefinitionRegistryPostProcessor,在处理过程中可能会有添加新的BeanDefinitionRegistryPostProcessor实现,// 然后重新获取,排除已执行的然后根据Ordered排序再执行实现了Ordered的// 上面两个都执行完成之后,不可避免的还会有其他的BeanDefinitionRegistryPostProcessor实现// 最后就再把剩余的BeanDefinitionRegistryPostProcessor实现再循环处理// 循环的原因也是因为在执行的过程中可能会有新的BeanDefinitionRegistryPostProcessor实现添加,所以循环执行所有的// Now, invoke the postProcessBeanFactory callback of all processors handled so far.// 到这里再调用到目前为止处理的所有处理器的 postProcessBeanFactory 回调  也就是本方法入参beanFactoryPostProcessors进来的那几个// 其实就是BeanFactoryPostProcessor的postProcessBeanFactoryinvokeBeanFactoryPostProcessors(registryProcessors, beanFactory);invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);}else{// Invoke factory processors registered with the context instance.invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let the bean factory post-processors apply to them!// 不要在此处初始化 FactoryBeans:我们需要让所有常规 bean 保持未初始化状态,以便 bean 工厂后处理器应用到它们!// 从工厂中查找BeanFactoryPostProcessor的实现String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class,true,false);// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,// Ordered, and the rest.// 将实现 PriorityOrdered、Ordered、其余部分 的 BeanFactoryPostProcessor 分组List<BeanFactoryPostProcessor> priorityOrderedPostProcessors =newArrayList<>();List<String> orderedPostProcessorNames =newArrayList<>();List<String> nonOrderedPostProcessorNames =newArrayList<>();for(String ppName : postProcessorNames){if(processedBeans.contains(ppName)){// 跳过在上面已经执行过的,其实在我们的例子中这里跳过的就是上面执行过的ConfigurationClassPostProcessor// skip - already processed in first phase above}elseif(beanFactory.isTypeMatch(ppName,PriorityOrdered.class)){
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName,BeanFactoryPostProcessor.class));}elseif(beanFactory.isTypeMatch(ppName,Ordered.class)){
            orderedPostProcessorNames.add(ppName);}else{
            nonOrderedPostProcessorNames.add(ppName);}}// 然后再根据分组结果,依次执行BeanFactoryPostProcessor的处理流程// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.// 首先,调用实现 PriorityOrdered 的 BeanFactoryPostProcessorsortPostProcessors(priorityOrderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);// Next, invoke the BeanFactoryPostProcessors that implement Ordered.// 接下来,调用实现 Ordered 的 BeanFactoryPostProcessorsList<BeanFactoryPostProcessor> orderedPostProcessors =newArrayList<>(orderedPostProcessorNames.size());for(String postProcessorName : orderedPostProcessorNames){
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName,BeanFactoryPostProcessor.class));}sortPostProcessors(orderedPostProcessors, beanFactory);invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);// Finally, invoke all other BeanFactoryPostProcessors.// 最后,调用所有其他 BeanFactoryPostProcessorList<BeanFactoryPostProcessor> nonOrderedPostProcessors =newArrayList<>(nonOrderedPostProcessorNames.size());for(String postProcessorName : nonOrderedPostProcessorNames){
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName,BeanFactoryPostProcessor.class));}invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);// Clear cached merged bean definitions since the post-processors might have// modified the original metadata, e.g. replacing placeholders in values...
    beanFactory.clearMetadataCache();}

上面这段源码贴出来,并写了一些注释,主要是说明了这个方法的大体执行逻辑,我们本篇分析的是

@Bean

的原理,所以我们重点看其中的:

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

这一步(源码中注释标记“!!!!!!”的那一步),也就是实现了

PriorityOrdered

BeanDefinitionRegistryPostProcessor

处理。

在进行重点源码分析前先说一下为什么在

beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

这一步能获取到

org.springframework.context.annotation.internalConfigurationAnnotationProcessor

,原因是SpringBoot在启动时候,

org.springframework.boot.SpringApplication#run(java.lang.String...)

方法中有一步:

context = createApplicationContext();

,其中创建了容器:

org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext

,在实例化这个容器的时候,他的无参构造会执行到:

org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

这个方法,这个里面给Spring工厂中注册了

org.springframework.context.annotation.internalConfigurationAnnotationProcessor

,这一步大家可以找到地方自行断点查看,不是本篇的重点就不详细说了。

进入

invokeBeanDefinitionRegistryPostProcessors

方法:

privatestaticvoidinvokeBeanDefinitionRegistryPostProcessors(Collection<?extendsBeanDefinitionRegistryPostProcessor> postProcessors,BeanDefinitionRegistry registry){// 根据我们上面跟进的内容,这里的postProcessors只有一个值:ConfigurationClassPostProcessorfor(BeanDefinitionRegistryPostProcessor postProcessor : postProcessors){
        postProcessor.postProcessBeanDefinitionRegistry(registry);}}

所以我们跟进到

org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

看:

publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry){int registryId =System.identityHashCode(registry);if(this.registriesPostProcessed.contains(registryId)){thrownewIllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against "+ registry);}if(this.factoriesPostProcessed.contains(registryId)){thrownewIllegalStateException("postProcessBeanFactory already called on this post-processor against "+ registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);}

然后继续跟进到:

processConfigBeanDefinitions(registry);
publicvoidprocessConfigBeanDefinitions(BeanDefinitionRegistry registry){List<BeanDefinitionHolder> configCandidates =newArrayList<>();// 获取工厂中的BeanDefinitionNamesString[] candidateNames = registry.getBeanDefinitionNames();//循环所有的BeanNames 找出候选配置类for(String beanName : candidateNames){BeanDefinition beanDef = registry.getBeanDefinition(beanName);if(beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE)!=null){if(logger.isDebugEnabled()){
                logger.debug("Bean definition has already been processed as a configuration class: "+ beanDef);}}elseif(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)){// 在本例中这里其实就是SpringBoot的启动类   因为@SpringBootApplication注解是个组合注解,其中包含@Configuration注解
            configCandidates.add(newBeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no @Configuration classes were found// 如果没有找到 @Configuration 类,则立即返回if(configCandidates.isEmpty()){return;}// Sort by previously determined @Order value, if applicable// 按@Order 值排序(如果合适)
    configCandidates.sort((bd1, bd2)->{int i1 =ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 =ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());returnInteger.compare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application context// 检测通过应用程序上下文提供的任何自定义 bean 名称生成策略  默认没有SingletonBeanRegistry sbr =null;if(registry instanceofSingletonBeanRegistry){
        sbr =(SingletonBeanRegistry) registry;if(!this.localBeanNameGeneratorSet){BeanNameGenerator generator =(BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);if(generator !=null){this.componentScanBeanNameGenerator = generator;this.importBeanNameGenerator = generator;}}}if(this.environment ==null){this.environment =newStandardEnvironment();}// Parse each @Configuration class// 解析每个 @Configuration 类ConfigurationClassParser parser =newConfigurationClassParser(this.metadataReaderFactory,this.problemReporter,this.environment,this.resourceLoader,this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates =newLinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed =newHashSet<>(configCandidates.size());do{// 解析的重点方法  // 这里面会进行包扫描并处理@Bean等注解的解析,并封装成ConfigurationClass,设置对应的标记BeanMethod// 下面会展开分析这个方法  
        parser.parse(candidates);
        parser.validate();Set<ConfigurationClass> configClasses =newLinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif(this.reader ==null){this.reader =newConfigurationClassBeanDefinitionReader(
                    registry,this.sourceExtractor,this.resourceLoader,this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 到这里已经获取到所有的配置类并封装成ConfigurationClass// 通过ConfigurationClass的BeanMethod解析@Bean注解的相关内容并构造出要注册的对象的BeanDefinition// 最后注册到工厂中去// 这一步下面也会展开解析this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);

        candidates.clear();if(registry.getBeanDefinitionCount()> candidateNames.length){String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames =newHashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses =newHashSet<>();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(newBeanDefinitionHolder(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 instanceofCachingMetadataReaderFactory){// 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();}}

这个方法大家看下注释,我们重点看下面这两个方法:

  • parser.parse(candidates);
  • this.reader.loadBeanDefinitions(configClasses); 这两个方法是核心,依次分开解析:

3.1 parser.parse(candidates)解析

进入源码:

org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)

跟进:

publicvoidparse(Set<BeanDefinitionHolder> configCandidates){for(BeanDefinitionHolder holder : configCandidates){BeanDefinition bd = holder.getBeanDefinition();try{if(bd instanceofAnnotatedBeanDefinition){// 注解类型的BeanDefinition 我们的SpringBoot启动类会进入这个  所以进入这个parse方法parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}elseif(bd instanceofAbstractBeanDefinition&&((AbstractBeanDefinition) bd).hasBeanClass()){parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else{parse(bd.getBeanClassName(), holder.getBeanName());}}catch(BeanDefinitionStoreException ex){throw ex;}catch(Throwable ex){thrownewBeanDefinitionStoreException("Failed to parse configuration class ["+ bd.getBeanClassName()+"]", ex);}}this.deferredImportSelectorHandler.process();}

跟进

parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

来到:

org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
protectedvoidprocessConfigurationClass(ConfigurationClass configClass,Predicate<String> filter)throwsIOException{if(this.conditionEvaluator.shouldSkip(configClass.getMetadata(),ConfigurationPhase.PARSE_CONFIGURATION)){return;}// 这里是第一次加载 所以肯定是空的ConfigurationClass existingClass =this.configurationClasses.get(configClass);if(existingClass !=null){if(configClass.isImported()){if(existingClass.isImported()){
                existingClass.mergeImportedBy(configClass);}// Otherwise ignore new imported config class; existing non-imported class overrides it.return;}else{// Explicit bean definition found, probably replacing an import.// Let's remove the old one and go with the new one.this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// Recursively process the configuration class and its superclass hierarchy.// 递归处理配置类及其超类层次结构// 这一步是做校验并封装成SourceClass SourceClass sourceClass =asSourceClass(configClass, filter);do{// 循环递归处理 
        sourceClass =doProcessConfigurationClass(configClass, sourceClass, filter);}while(sourceClass !=null);// 处理完成后加入缓存this.configurationClasses.put(configClass, configClass);}

详细看:

doProcessConfigurationClass(configClass, sourceClass, filter);

org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
protectedfinalSourceClassdoProcessConfigurationClass(ConfigurationClass configClass,SourceClass sourceClass,Predicate<String> filter)throwsIOException{// 是不是有Component注解  启动类的@SpringBootApplication注解中有Component注解 所以会进入ifif(configClass.getMetadata().isAnnotated(Component.class.getName())){// Recursively process any member (nested) classes first// 首先递归处理任何成员(嵌套)类   这个类没有嵌套  所以略过processMemberClasses(configClass, sourceClass, filter);}// Process any @PropertySource annotations// 处理任何 @PropertySource 注释   没有这个注释所以跳过for(AnnotationAttributes propertySource :AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(),PropertySources.class,org.springframework.context.annotation.PropertySource.class)){if(this.environment instanceofConfigurableEnvironment){processPropertySource(propertySource);}else{
            logger.info("Ignoring @PropertySource annotation on ["+ sourceClass.getMetadata().getClassName()+"]. Reason: Environment must implement ConfigurableEnvironment");}}// Process any @ComponentScan annotations// 处理任何@ComponentScan注释      @SpringBootApplication注解中有@ComponentScan注解 所以会获取到一个AnnotationAttributesSet<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 immediately// 配置类使用 @ComponentScan 注解 -> 立即执行扫描// 这一步是重点  下面会展开解析Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if needed// 检查扫描出来的Bean定义,如果需要并循环解析更深层级的配置for(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 annotations// 处理任何 @Import 注释processImports(configClass, sourceClass,getImports(sourceClass), filter,true);// Process any @ImportResource annotations// 处理任何 @ImportResource 注释AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(),ImportResource.class);if(importResource !=null){String[] resources = importResource.getStringArray("locations");Class<?extendsBeanDefinitionReader> readerClass = importResource.getClass("reader");for(String resource : resources){String resolvedResource =this.environment.resolveRequiredPlaceholders(resource);
            configClass.addImportedResource(resolvedResource, readerClass);}}// Process individual @Bean methods// 处理单个 @Bean 方法Set<MethodMetadata> beanMethods =retrieveBeanMethodMetadata(sourceClass);// 获取到所有的@Bean方法的元数据for(MethodMetadata methodMetadata : beanMethods){// 封装成BeanMethod添加到ConfigurationClass
        configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));}// Process default methods on interfaces// 处理接口上的默认方法processInterfaces(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 completereturnnull;}

上面这段代码步骤是:

  1. 先处理@Component的嵌套类
  2. 再处理@PropertySource
  3. 再处理@ComponentScan,这一步是包扫描的重点过程,扫描到包路径下的所有符合条件的Bean并封装成BeanDefinitionHolder返回
  4. 再处理@Import
  5. 再处理@ImportResource
  6. 再处理@Bean,将扫描出来的所有@Bean元数据记录下来
  7. 再处理接口上的@Bean
  8. 如果有父类处理父类

我们重点来看

@ComponentScan

的这一步,所以跟进

this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
publicSet<BeanDefinitionHolder>parse(AnnotationAttributes componentScan,finalString declaringClass){// 创建BeanDefinition的扫描器ClassPathBeanDefinitionScanner scanner =newClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"),this.environment,this.resourceLoader);//获取@ComponentScan注解的nameGenerator ClassClass<?extendsBeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");boolean useInheritedGenerator =(BeanNameGenerator.class== generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ?this.beanNameGenerator :BeanUtils.instantiateClass(generatorClass));//获取@ComponentScan注解的scopedProxyScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");if(scopedProxyMode !=ScopedProxyMode.DEFAULT){
        scanner.setScopedProxyMode(scopedProxyMode);}else{Class<?extendsScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));}//获取@ComponentScan注解的resourcePattern
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));//获取@ComponentScan注解的includeFiltersfor(AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")){for(TypeFilter typeFilter :typeFiltersFor(filter)){
            scanner.addIncludeFilter(typeFilter);}}//获取@ComponentScan注解的excludeFiltersfor(AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")){for(TypeFilter typeFilter :typeFiltersFor(filter)){
            scanner.addExcludeFilter(typeFilter);}}//获取@ComponentScan注解的lazyInitboolean lazyInit = componentScan.getBoolean("lazyInit");if(lazyInit){
        scanner.getBeanDefinitionDefaults().setLazyInit(true);}Set<String> basePackages =newLinkedHashSet<>();// 获取@ComponentScan注解的basePackages  // 获取配置的扫描包路径,这个大家应该用过,有时候会在启动类上配置这个用来自定义包扫描路径// 在我们的例子中是没有配置的  所有这个为空String[] basePackagesArray = componentScan.getStringArray("basePackages");for(String pkg : basePackagesArray){String[] tokenized =StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);Collections.addAll(basePackages, tokenized);}for(Class<?> clazz : componentScan.getClassArray("basePackageClasses")){
        basePackages.add(ClassUtils.getPackageName(clazz));}// 如果没有配置basePackages   那么取启动类所在的包路径!!!if(basePackages.isEmpty()){
        basePackages.add(ClassUtils.getPackageName(declaringClass));}

    scanner.addExcludeFilter(newAbstractTypeHierarchyTraversingFilter(false,false){@OverrideprotectedbooleanmatchClassName(String className){return declaringClass.equals(className);}});// 根据获取到的包路径进行扫描  在我们的例子中这里就是启动类所在的包com.ygz.test1return scanner.doScan(StringUtils.toStringArray(basePackages));}

这段代码主要是解析

@ComponentScan

注解的元数据,并获取到要扫描的包路径,代码不难就不细说了大家看注释就行,我们接着跟进到

scanner.doScan(StringUtils.toStringArray(basePackages));
protectedSet<BeanDefinitionHolder>doScan(String... basePackages){Assert.notEmpty(basePackages,"At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions =newLinkedHashSet<>();// 循环要扫描的包路径  我们的例子中只有一个for(String basePackage : basePackages){// 通过包路径进行扫描 把所有扫描出来的Bean封装成BeanDefinition返回出来// 这一步其实就是spring的Bean扫描流程了,本篇主要是@Bean的解析过程,这里就不深入跟进了,里面内容较多  大家可以自行debug查看Set<BeanDefinition> candidates =findCandidateComponents(basePackage);// 这个循环主要是把获取到的BeanDefinition做进一步的处理// 设置scope、设置其他的一些属性、检查是否需要代理需要的话创建代理等  最终把这个BeanDefinition 注册到工厂中for(BeanDefinition candidate : candidates){ScopeMetadata scopeMetadata =this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());String beanName =this.beanNameGenerator.generateBeanName(candidate,this.registry);if(candidate instanceofAbstractBeanDefinition){postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if(candidate instanceofAnnotatedBeanDefinition){AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if(checkCandidate(beanName, candidate)){BeanDefinitionHolder definitionHolder =newBeanDefinitionHolder(candidate, beanName);
                definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder,this.registry);
                beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder,this.registry);}}}return beanDefinitions;}

到这里就已经扫描到所有的Bean的

BeanDefinition

并注册到工厂了,返回所有的

BeanDefinition

,然后我们回到

org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

方法的解析

@ComponentScan

代码位置,通过

Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

这一步拿到了扫描出来的所有

BeanDefinition 

,然后循环每一个并检查是不是配置类,然后如果是配置类,那么再次调用解析方法解析配置类,这里其实类似递归过程。下面把这部分代码再贴出来一下

// 这一段是org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass方法解析@ComponentScan注解的部分代码// The config class is annotated with @ComponentScan -> perform the scan immediately// 通过@ComponentScan扫描出所有的Bean并获取到BeanDefinitionHolderSet<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// Check the set of scanned definitions for any further config classes and parse recursively if needed// 循环判断是不是配置类,如果是配置类那么继续递归解析for(BeanDefinitionHolder holder : scannedBeanDefinitions){BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if(bdCand ==null){
        bdCand = holder.getBeanDefinition();}// 在我们的例子中,TestConfig类标记有@Configuration注解,所以是配置类,会进入这个if// 然后会在parse方法中继续递归的去解析TestConfig类,在解析到@Bean注解的时候就会把TestConfig类的myTest()方法扫描出来// 这里这个递归大家要能理解,这里第一次parse是通过SpringBoot的启动类扫描所有的Bean// 获取到所有的BeanDefinition之后循环每一个,查看是不是配置类,如果是配置类那么递归调用parse方法// 比如在我们的例子中TestConfig被启动类扫描到之后,会在这里再次被parse,然后再次进入本方法(就是doProcessConfigurationClass)// 当再次进入之后,TestConfig中有方法myTest()标记了@Bean注解  那么就会被@Bean注解处理流程处理 这个处理我们下面会跟进// 这里大家要弄清楚这个递归流程  如果看文章看不明白可以debug跟进查看if(ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand,this.metadataReaderFactory)){parse(bdCand.getBeanClassName(), holder.getBeanName());}}

在上面这段代码中

ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)

这个判断里有一个小细节这里提一下,我们直接看这段代码中的部分(不把代码全贴出来,大家可以自己点进源码看):

Map<String,Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());if(config !=null&&!Boolean.FALSE.equals(config.get("proxyBeanMethods"))){
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);}elseif(config !=null||isConfigurationCandidate(metadata)){
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);}else{returnfalse;}

这段代码中有一个获取

@Configuration

注解的

proxyBeanMethods

属性值的判断,这个其实是Spring配置类的一种类型/模式,具体这里也不分析了有点脱离主题,直接贴一下结论:
如果 Class上标注有@Component注解、@ComponentScan注解、@Import注解、@ImportResource注解、类上没有任何注解,存在@Bean方法、@Configuration(proxyBeanMethods = false) 这几种情况下认为是lite模式的配置类
那么对应的full模式就是上面代码中判断的@Configuration(proxyBeanMethods = true)这种情况下认为是 full模式
那么fulllite模式的区别是什么呢?
对于full模式:full模式下的配置类会被CGLIB代理生成代理类取代原始类型(在容器中);full模式下的@Bean方法不能是private和final;单例scope下不同@Bean方法可以互相引用,达到单实例的语义
对于lite模式:lite模式下的配置类不生成代理,原始类型进入容器;lite模式下的@Bean方法可以是private和final;单例scope下不同@Bean方法引用时无法做到单例

好了关于fulllite模式就简单说这些,感兴趣的小伙伴可以再深入研究,细讲篇幅实在太长了,我们回到正题。

至此我们分析完了从SpringBoot启动类进入包扫描,然后获取所有扫描到的Bean对象的

BeanDefinition

,然后递归处理再次解析配置类,当被扫描到的Bean有@Bean注解时,会走

org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

方法的@Bean注解处理流程,也就是这部分:

//这部分代码是org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass的一小段//这段专门处理@Bean注解的// Process individual @Bean methods// 通过上面的分析我们知道了,对于我们例子中TestConfig类中有@Bean注解,所以我们这里认为代码运行到parse到TestConfig了// 然后下面这一步的sourceClass其实就是TestConfig的SourceClass对象,在这一步获取TestConfig中的@Bean标记的方法// 这个就不跟进去分析了  这一步获取到的就是Bean里面所有的@Bean标记的方法Set<MethodMetadata> beanMethods =retrieveBeanMethodMetadata(sourceClass);// 然后循环把这些添加到configClass记录for(MethodMetadata methodMetadata : beanMethods){
    configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));}

那么至此,经过SpringBoot启动类扫描了所有Bean,然后所有扫描出来的Bean也递归的parse完成了,那么就返回到

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

方法中的

parser.parse(candidates);

这一步,经过这些步骤之后,扫描到的所有的Bean对应的

BeanDefinition

也注册完成了。然后我们来看接下来该方法中的:

this.reader.loadBeanDefinitions(configClasses);

3.2 this.reader.loadBeanDefinitions(configClasses)解析

org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

方法中调用

this.reader.loadBeanDefinitions(configClasses);

时会传入之前已解析到的所有

ConfigurationClass

,这个Set有很多值,但是我们本次只分析

@Bean

的内容,所以我们就看

TestConfig

类的流程。跟进

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

方法:

publicvoidloadBeanDefinitions(Set<ConfigurationClass> configurationModel){// 传入了所有的ConfigurationClassTrackedConditionEvaluator trackedConditionEvaluator =newTrackedConditionEvaluator();for(ConfigurationClass configClass : configurationModel){// 由于我们只分析@Bean注解,所以我们就当成本次循环到了TestConfig类,然后跟进下面这个方法loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}

跟进

loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);

方法(假设此时入参是

TestConfig

ConfigurationClass

)

privatevoidloadBeanDefinitionsForConfigurationClass(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);}// 前面我们分析的parse方法递归的过程中,TestConfig的@Bean方法会加载成MethodMetadata并添加到了configClass的BeanMethods中// 这里就是把之前解析并记录的BeanMethod 取出来循环loadfor(BeanMethod beanMethod : configClass.getBeanMethods()){// load每一个BeanMethod 并转成BeanDefinition注册当工厂中loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());}

通过上面这段代码我们跟进:

loadBeanDefinitionsForBeanMethod(beanMethod);
privatevoidloadBeanDefinitionsForBeanMethod(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;}//获取@Bean注解的属性值AnnotationAttributes bean =AnnotationConfigUtils.attributesFor(metadata,Bean.class);Assert.state(bean !=null,"No @Bean annotation attributes");// Consider name and any aliases// 获取Bean的名称和别名List<String> names =newArrayList<>(Arrays.asList(bean.getStringArray("name")));// 如果@Bean注解的name属性为空,那么获取@Bean注解标记的方法的名字为beanName  否则就取name属性的第一个的值并将其删除// 在我们的例子TestConfig中,@Bean并没有name属性设置,所以@Bean标记方法生成的spring Bean对象的名称就是方法名:myTestString 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())){thrownewBeanDefinitionStoreException(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 =newConfigurationClassBeanDefinition(configClass, metadata, beanName);
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));if(metadata.isStatic()){// static @Bean methodif(configClass.getMetadata()instanceofStandardAnnotationMetadata){
            beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());}else{
            beanDef.setBeanClassName(configClass.getMetadata().getClassName());}
        beanDef.setUniqueFactoryMethodName(methodName);}else{// instance @Bean method
        beanDef.setFactoryBeanName(configClass.getBeanName());
        beanDef.setUniqueFactoryMethodName(methodName);}if(metadata instanceofStandardMethodMetadata){
        beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());}

    beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
            SKIP_REQUIRED_CHECK_ATTRIBUTE,Boolean.TRUE);AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);Autowire autowire = bean.getEnum("autowire");if(autowire.isAutowire()){
        beanDef.setAutowireMode(autowire.value());}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);// 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 necessary// 如有必要,将原始 bean 定义替换为代理目标BeanDefinition beanDefToRegister = beanDef;if(proxyMode !=ScopedProxyMode.NO){BeanDefinitionHolder proxyDef =ScopedProxyCreator.createScopedProxy(newBeanDefinitionHolder(beanDef, beanName),this.registry,
                proxyMode ==ScopedProxyMode.TARGET_CLASS);
        beanDefToRegister =newConfigurationClassBeanDefinition((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));}// 到这里 @Bean标记的方法就被加载成BeanDefinition 并注入到工厂中this.registry.registerBeanDefinition(beanName, beanDefToRegister);}

那么至此被扫描的配置类中

@Bean

标记的方法的

BeanDefinition

也被注册到工厂中了,后续在

org.springframework.context.support.AbstractApplicationContext#refresh

中实例化的时候,该对象就会被实例化并交由Spring管理,也就分析完了

@Bean

注解的家在过程。

最后再说一下本篇分析的是

@Configuration

注解下

@Bean

的加载过程,类似

@Component

注解下也可以加载

@Bean

,流程和

@Configuration

基本类似,大家可以debug跟进一下。好了分析完成!

标签: spring java spring boot

本文转载自: https://blog.csdn.net/qq_34203492/article/details/126505543
版权归原作者 景川呀 所有, 如有侵权,请联系我们删除。

“Spring的@Bean注解原理详解”的评论:

还没有评论