SpringBoot自动装配代码演示

想了解springboot的自动装配原理,但是又不知道怎么跟代码看,跟我来~

1. 首先,创建一个springboot的项目(我的叫demo1)

 F7, 进入

此时,primarySource是class com.example.demo.Demo1Application

再次F7

 再次F7, 进new SpringApplication方法

F7,到了SpringApplication的构造方法中

 F8,执行到 this.setInitializers,F7,进入getSpringFactoriesInstances方法

F7

F8, 执行到第二行,

F7,进入SpringFactoriesLoader.loadFactoryNames方法

 F8,执行到

(List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());

然后F7,进入

loadSpringFactories

 F8,加载spring.factories文件

F8执行完后,读取到了7个配置

是spring-boot包和spring-boot-autoconfigure包的spring.factories中的ApplicationContextInitializer的配置


执行到SpringApplication的主方法中,

执行完,继续执行this.setInitializers后,initializers的值是刚刚加载的配置类

 同理, 执行完

this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));

listeners的值也是spring.factories中的ApplicationListener相应的配置类

当启动springboot应用程序的时候, 会先创建SpringApplication的对象,在对象的构造方法中会进行某些参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在这个过程中会加载整个应用程序中的spring.factories文件,将文件的内容放到缓存对象中,方便后续获取。

 执行完SpringApplication的方法后,进入run方法

2.run方法

 run方法中有两个重要的方法prepareContext和refreshContext方法

SpringApplication对象创建完成之后,开始执行run方法,来完成整个启动过程。启动过程中最主要的有两个方法,第一个叫做prepareContext,第二个叫做refreshContext,在这两个关键步骤中完成了自动装配的核心功能。前面的处理逻辑包含了上下文对象的创建,banner的打印,异常报告器的准备等各个准备工作,方便后续来进行调用

 3. prepareContext

prepareContext方法中有一个重要的方法,load方法

 F7进入load方法

 再进入loader.load()方法

F7进入this.load()方法

 再次进入this.load()方法

 F7进入register方法

 加载主类Demo1Application到register中

 在prepareContext方法中主要完成的是对上下文对象的初始化操作,包括了属性值的设置,比如环境对象。在整个过程中有一个非常重要的方法,叫做load。load主要完成一件事,将当前启动类做为一个beanDefinition注册到registry中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的主类,来完成@SpringBootApplicaiton,@EnableAutoConfiguration等注解的解析工作

4. 执行this.refreshContext

F7进入

F7进入

 进入this.refresh方法, 继续F7直到进入AbstractApplicationContext的refresh()方法,该方法是spring中重要的方法,其中包含了13个重要的方法。

 在自动装配过程中,会调用invokeBeanFactoryPostProcessor方法

 进入

invokeBeanFactoryPostProcessors,此方法主要识别应用程序中有哪些BeanFactoryPostProcessor,识别到之后会进行执行;但是,这个接口还有一个子接口BeanDefinitionRegisterPostProcessor;所以先判断是不是实现了BeanDefinitionRegisterPostProcessor,如果实现了的话,先执行BeanDefinitionRegisterPostProcessor的方法(postProcessorBeanDefinitionRegister),再执行BeanFactoryPostProcessor的方法(postProcessorBeanFactory)

 在86行取出

String[] postProcessorNames =
      beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

值是:org.springframework.context.annotation.internalConfigurationAnnotationProcessor 

在AnnotationConfigUtils类中有关于org.springframework.context.annotation.internalConfigurationAnnotationProcessor的转换

 下面有判断如果不包含CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME的beanDefinition,就创建ConfigurationClassPostProcessor类的对象

打开ConfigurationClassPostProcessor类,它实现了BeanDefinitionRegistryPostProcessor接口,所以在执行的时候,先执行BeanDefinitionRegistryPostProcessor的postProcessorBeanDefinitionRegister方法,再执行BeanFactoryPostProcessor的postProcessorBeanFactory方法

 继续执行,

currentRegistryProcessors中有一个结果ConfigurationClassPostProcessor

F7进入

F7进入

 F7进入processConfigBeanDefinitions

此时candidateNames有7个值,其中6个值都是internal,不用处理,只用处理主类demo1Application。因为在前面prepareContext方法中有this.register.add(xxx), 把主类加载到register中了

 继续执行,到parser.parse()方法开始解析

F7进去 

进入parse 

 F7

doProcessConfigurationClass中有一系列相关注解的解析工作

 解析@PropertySource、@ComponentScan、@Import、@ImportResource注解

5. @Import注解解析 

重点关注@Import注解,F7进入getImports方法(等到sourceClass是主类的时候进入)

进入collectImports方法,递归遍历@Import注解

判断当前类注解是不是@Import,不是的话,递归调用

@SpringBootApplication

        @SpringBootConfiguration

        @EnableAutoConfiguration

                @AutoConfiguration

                        @Import({Registrar.class})

               @Import({AutoConfigurationImportSelector.class})

        @ComponentScan

 getImports的结果有两个

 继续进入processImports方法

 

 其中,@Import({Registrar.class})属于ImportBeanDefinitionRegistrar.class类型,把当前类加到ImportBeanDefinitionRegistrar中

@Import({AutoConfigurationImportSelector.class})属于ImportSelector.class类型

把select对象加入deferredImportSelectorHandler中进行处理

 进入this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);

把holder对象加入到deferredImportSelectors中

继续处理@ImportSource、@Bean注解 

继续执行到这,处理 deferredImportSelectorHandler

 进入handler.processGroupImports();

进入grouping.getImports()

进入this.group.process

 进入getAutoConfigurationEntry方法

进入getCandidateConfigurations

 

进入getSpringFactoriesLoaderFactoryClass(),返回EnableAutoConfiguration.class;

 继续进入loadFactoryNames,加载EnableAutoConfiguration.class

 继续进入loadSpringFactories方法

此时,cache中有EnableAutoConfiguration

 继续执行,此时 configurations中有128个值,把所有包含在EnableAutoConfiguration中的值都加载回来

经过一系列筛选工作,还剩25个配置 ,此时自动装配完成

6.总结

 老师总结

1、当启动springboot应用程序的时候, 会先创建SpringApplication的对象,在对象的构造方法中会进行某些参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在这个过程中会加载整个应用程序中的spring.factories文件,将文件的内容放到缓存对象中,方便后续获取。

2、SpringApplication对象创建完成之后,开始执行run方法,来完成整个启动,启动过程中最主要的有两个方法,第一个叫做prepareContext,第二个叫做refreshContext,在这两个关键步骤中完成了自动装配的核心功能,前面的处理逻辑包含了上下文对象的创建,banner的打印,异常报告期的准备等各个准备工作,方便后续来进行调用。

3、在prepareContext方法中主要完成的是对上下文对象的初始化操作,包括了属性值的设置,比如环境对象,在整个过程中有一个非常重要的方法,叫做load,load主要完成一件事,将当前启动类做为一个beanDefinition注册到registry中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的主类,来完成@SpringBootApplicaiton,@EnableAutoConfiguration等注解的解析工作

4、在refreshContext方法中会进行整个容器刷新过程,会调用中spring中的refresh方法,refresh中有13个非常关键的方法,来完成整个spring应用程序的启动,在自动装配过程中,会调用invokeBeanFactoryPostProcessor方法,在此方法中主要是对ConfigurationClassPostProcessor类的处理,这是BFPP的子类也是BDRPP的子类,在调用的时候会先调用BDRPP中的postProcessBeanDefinitionRegistry方法,然后调用postProcessBeanFactory方法,在执行postProcessBeanDefinitionRegistry的时候回解析处理各种注解,包含@PropertySource,@ComponentScan,@ComponentScans,@Bean,@Import等注解,最主要的是@Import注解的解析

5、在解析@Import注解的时候,会有一个getImports的方法,从主类开始递归解析注解,把所有包含@Import的注解都解析到,然后在processImport方法中对Import的类进行分类,此处主要识别的是AutoConfigurationImportSelect归属于ImportSelect的子类,在后续过程中会调用deferredImportSelectorHandler中的process方法,来完成EnableAutoConfiguration的加载。

简化:

1、当启动springboot应用程序的时候, 会先new一个SpringApplication对象,在对象的构造方法中会加载spring.factories文件到缓存中。

2、SpringApplication对象创建完成之后,开始执行run方法,来完成整个启动。启动过程中最主要的有两个方法,第一个叫做prepareContext,第二个叫做refreshContext。

3、在prepareContext方法中有一个非常重要的load方法,load方法将当前启动类做为一个beanDefinition注册到registry中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的主类,来完成@SpringBootApplicaiton,@EnableAutoConfiguration等注解的解析工作

4、在refreshContext方法中会调用spring中的refresh方法中的invokeBeanFactoryPostProcessor方法。在此方法中主要是对ConfigurationClassPostProcessor类的处理,这是BFPP的子类也是BDRPP的子类,会先调用BDRPP中的方法,再调用BFPP中的方法。在执行postProcessBeanDefinitionRegistry的时候会解析@Import注解。

5、在解析@Import注解的时候,从主类开始递归解析注解,把所有包含@Import的注解都解析到。然后对Import类进行分类,主要识别的是AutoConfigurationImportSelect归属于ImportSelect的子类,在后续过程中会调用deferredImportSelectorHandler中的process方法,来完成EnableAutoConfiguration的加载。

 

自己总结


什么是自动装配
就是自动把其他组件中的bean加载到ioc中,不需要开发人员再去配置文件中添加大量的配置。我们只需要在springboot的启动类上添加一个@SpringBootApplication的一个注解,这样就可以开启自动装配。
还有比如使用redis的时候,会引入redis的依赖(spring-boot-stater-data-redis),引入依赖后,项目启动的时候,会将操作redis需要的组件注入到ioc容器中进行后续使用。

自动装配解决了什么问题
减少了臃肿的配置文件;各个模块直接的依赖也深度解耦了;
比如我们使用Spring创建Web程序的时候需要引用非常多的Maven依赖,而SpringBoot中只需要引用一个Maven依赖(spring-boot-starter-web)就可以来创建Web程序

自动装配原理
springboot自动装配主要是通过SpringFactoriesLoader加载spring.factories中的配置文件,将配置文件中的类加载到ioc容器中进行使用。

(其余的我还没有弄明白,待补充)


版权声明:本文为CelineT原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。