0


SpringBoot的自动装配

SpringBoot的自动装配

大致流程

  1. 当启动SpringBoot应用程序的时候,会先创建SpringApplication对象,在构造方法中会进行一些参数的初始化工作,比如会加载Spring.factories文件,将文件的内容放到缓存对象中,方便后续获取
  2. SpringApplication对象创建完成后,开始调用run方法,启动过程中最主要有两个方法,第一个叫prepareContext(),第二个叫refreshContext()方法
  3. 在prepareContext()方法主要是对上下文对象ConfigurableApplicationContext的初始化操作,在整个过程中有个非常重要的方法就是load()方法,它会将当前启动类作为一个BeanDefinition注册到BeanDefinitionMap中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的启动类,来完成对应注解的解析工作
  4. 在refreshContext()方法会进行整个Spring容器的刷新refresh操作,会调用spring的refresh()方法,自动装配过程是在invokeBeanFactoryPostProcessor方法()中进行(也就是执行BeanFactory的后置处理器),在此方法主要是针对ConfigurationClassPostProcessor类的处理
  5. 在执行BeanFactory后置处理器的时候会调用ConfigurationClassPostProcessor类中的parse()方法去解析处理各种注解比如@CompomentScan、@Import等等
  6. 在解析@Import注解的时候比较特别,会有一个collectImports()方法,从主类开始递归解析注解,把所有包含@Import的注解都解析到BeanDefinitionMap中
  7. 调用AutoConfigurationImportSelector类(相当于一个处理器)中的process()方法进而触发getCandidateConfigurations()方法获取Spring.factories文件下的key为EnableAutoConfiguration的所有value,所以这就是为什么很多人的文章中都说Springboot的自动装配就是调用@EnableAutoConfiguration注解下的@Import中的AutoConfigurationImportSelector类,主要就是通过这种不断解析注解的方法去调用的

在这里插入图片描述

  1. 将所有解析到的注解的类都注册到BeanDifinitionMap中
  2. 至此就完成了SpringBoot的自动装配

完整流程(结合源码)

启动类
@SpringBootApplicationpublicclassTest{publicstaticvoidmain(String[] args){SpringApplication.run(Test.class, args);System.out.println("启动成功");}}
SpringApplication的构造方法
publicSpringApplication(ResourceLoader resourceLoader,Class<?>... primarySources){// 初始化this.resourceLoader = resourceLoader;Assert.notNull(primarySources,"PrimarySources must not be null");this.primarySources =newLinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType =WebApplicationType.deduceFromClasspath();// 加载Spring.factories文件,将文件的内容放到缓存对象中,方便后续获取setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));// 设置监听器setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));// 将mainApplicationClass属性设置为当前类Test的Clas对象this.mainApplicationClass =deduceMainApplicationClass();}
run方法
publicConfigurableApplicationContextrun(String... args){// 省略代码try{// 准备环境,这里的environment环境包括系统环境,比如jvm的参数等等ConfigurableEnvironment environment =prepareEnvironment(listeners, applicationArguments);// 准备Banner,即每次启动项目的时候控制台都会出现一个很大的图像Banner printedBanner =printBanner(environment);// 创建上下文对象
        context =createApplicationContext();// 准备上下文对象prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新上下文对象refreshContext(context);// 省略代码}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);}}
prepareContext()方法

准备上下文对象,将springApplicationArguments对象和springBootBanner对象放入Spring一级缓存singletonObjects中

privatevoidprepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment environment,SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments,Banner printedBanner){// 省略代码// 获取Beanfactory对象ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 将springApplicationArgusments放到一级缓存中
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);// 将springBootBanner放到一级缓存中if(printedBanner !=null){
        beanFactory.registerSingleton("springBootBanner", printedBanner);}// 加载资源,也就是将当前的启动类Test Class对象放到Set中Set<Object> sources =getAllSources();// 见下load(context, sources.toArray(newObject[0]));// 将上下文加载到监听器中
    listeners.contextLoaded(context);}
load()方法

将当前启动类作为一个BeanDefinition加载到BeanDefinitionMap中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的启动类,来完成对应注解的解析工作

privateintload(Class<?> source){// 判断启动类上有没有@Component注解if(isComponent(source)){// 若有则将当前启动类作为一个BeanDefinition注册到BeanDifinitionMap中this.annotatedReader.register(source);return1;}return0;}
refreshContext()方法

执行完prepareContext()方法后,调用Spring的刷新容器方法refresh()

privatevoidrefreshContext(ConfigurableApplicationContext context){// 调用Spring的刷新容器方法refresh(context);}
refresh()方法

这个方法相信大家非常熟悉了吧,那完成Springboot自动装配过程是在哪个阶段发生的呢?其实就是在invokeBeanFactoryPostProcessors()方法实现的

// 伪代码,方法在AbstractApplicationContext类中publicvoidrefresh()throwsBeansException,IllegalStateException{// 执行BeanFactory的后置处理器,自动装配中此方法主要是针对ConfigurationClassPostProcessor类的处理invokeBeanFactoryPostProcessors(beanFactory);}
invokeBeanFactoryPostProcessors()方法

这里主要就是处理BeanFactory后置处理器,也就是直接或者间接实现BeanFactoryPostProcessor的接口的类,主要调用的是ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry()方法

publicstaticvoidinvokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory,List<BeanFactoryPostProcessor> beanFactoryPostProcessors){if(beanFactory instanceofBeanDefinitionRegistry){BeanDefinitionRegistry registry =(BeanDefinitionRegistry) beanFactory;for(BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors){if(postProcessor instanceofBeanDefinitionRegistryPostProcessor){BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;// 主要就是这个方法
                registryProcessor.postProcessBeanDefinitionRegistry(registry);}}}}
ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法

此方法作用就是去解析处理各种注解比如@CompomentScan、@Import等等注解

publicvoidprocessConfigBeanDefinitions(BeanDefinitionRegistry registry){// ...List<BeanDefinitionHolder> configCandidates =newArrayList<>();// 获取对应的BeanDifinitionMap中的BeanDefinitionNameString[] candidateNames = registry.getBeanDefinitionNames();// 创建注解解析器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{// 进行注解解析
        parser.parse(candidates);}while(!candidates.isEmpty());// ...}
ConfigurationClassParser类中的parse()方法

解析注解的入口

publicvoidparse(Set<BeanDefinitionHolder> configCandidates){for(BeanDefinitionHolder holder : configCandidates){BeanDefinition bd = holder.getBeanDefinition();if(bd instanceofAnnotatedBeanDefinition){// 具体的解析注解的方法parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}}this.deferredImportSelectorHandler.process();}
ConfigurationClassParser类中的doProcessConfigurationClass()方法

到达解析注解的最终方法,将解析到的Bean注册到BeanDifinitionMap中

protectedfinalSourceClassdoProcessConfigurationClass(ConfigurationClass configClass,SourceClass sourceClass)throwsIOException{// 解析@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");}}// 解析@ComponentScan注解Set<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());}}}}// 解析@Import注解processImports(configClass, sourceClass,getImports(sourceClass),true);// 解析@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);}}// 解析@Bean注解Set<MethodMetadata> beanMethods =retrieveBeanMethodMetadata(sourceClass);for(MethodMetadata methodMetadata : beanMethods){
        configClass.addBeanMethod(newBeanMethod(methodMetadata, configClass));}returnnull;}
AutoConfigurationImportSelector类中的process()方法

这里的作用是读取Spring.factories文件中的内容,将所有的第三方的starter装载到BeanDefinitionMap中

publicvoidprocess(AnnotationMetadata annotationMetadata,DeferredImportSelector deferredImportSelector){// getAutoConfigurationEntry()方法读取Spring.factories文件中的内容入口AutoConfigurationEntry autoConfigurationEntry =((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);this.autoConfigurationEntries.add(autoConfigurationEntry);for(String importClassName : autoConfigurationEntry.getConfigurations()){this.entries.putIfAbsent(importClassName, annotationMetadata);}}
至此,springboot的自动装配就完成了

创作不易,希望大家能够点个赞,也希望大家能帮忙指出问题,一起进步!!!谢谢大家~~
在这里插入图片描述

标签: spring boot spring java

本文转载自: https://blog.csdn.net/weixin_42119730/article/details/127522419
版权归原作者 99Savage 所有, 如有侵权,请联系我们删除。

“SpringBoot的自动装配”的评论:

还没有评论