本文主要介绍
1. Spring Boot是如何完成自动装配的
2.Spring Boot核心启动类方法的执行流程
1. Spring Boot是如何完成自动装配的
概念
- 自动装配:根据我们在POM中添加的jar依赖,Spring Boot会自动将一些配置类的bean注入到IOC容器中,在项目中,我们可以直接通过 @Autowired,@resourecs就可以直接使用
Spring Boot主程序类会使用@SpringBootApplication进行标注
如图可见@SpringBootApplication为组合注解
层层剖析后,本质将主程序类定义为@Configuration配置类,@ComponentScan定义包扫描(默认为主程序类所在包路径);以及向容器中导入组件类 AutoConfigurationImportSelector.class及 AutoConfigurationPackages.Registrar.class
1. 在AutoConfigurationImportSelector类的内部类AutoConfigurationGroup中定义了process()及selectImports(),在这两个方法中,将会
A.从spring.factories配置文件中加载自动配置类(所有META-INF下名字为spring.factories的配置中key为EnableAutoConfiguration全路径类名)
B. 加载的自动配置类中排除掉不需要自动配置的类;比如: @EnableAutoConfiguration 注解的 exclude 属性指定的,配置类中有些有标准是否配置的条件注解,不满足@ConditionalOnClass , @ConditionalOnBean 和 @ConditionalOnWebApplication 的条件也过滤掉;等
C. @Order注解的自动配置类进行排序
D.将符合条件的类信息存放到集合中
在Spring Boot的核心run方法中,在初始化了Spring上下文对象后,刷新上下文时 ,会调用SpringIOC的核心方法:refresh方法,refresh在调用invokeBeanFactoryPostProcessors即BeanFactory 的后处理器方法中,在解析BeanDefiniction时最终会调用到AutoConfigurationImportSelector类的内部类AutoConfigurationGroup中定义了process()及selectImports()方法. 将最后筛选出的自动配置类导入IOC容器中;从而实现自动装配
2.Spring Boot核心启动类方法的执行流程
Spring Boot主程序会调用SpringApplication的run方法,传入主方法类信息及主函数参数信息
SpringApplication.run(MyTestApplication.class, args);
在run方法的重载方法中
会初始化SpringApplication以及调用run方法
new SpringApplication(primarySources).run(args)
在SpringApplication的初始化方法中推断应用类型,初始化spring.factories中已配置的ApplicationContextInitializer及 ApplicationListener;根据方法调用栈,推断出 main 方法的类名
在run方法中运行spring应用,并刷新一个新的 ApplicationContext(Spring的上下文)即:ConfigurableApplicationContext对象
依次完成获取并启动监听器,构建应用上下文环境(args),初始化应用上下文,刷新上下文对象等从而启动项目;
public ConfigurableApplicationContext run(String... args) {
//记录程序运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// ConfigurableApplicationContext Spring 的上下文
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//【1、获取并启动监听器】
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//【2、构造应用上下文环境】
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//处理需要忽略的Bean
configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = printBanner(environment);
///【3、初始化应用上下文】 //org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
context = createApplicationContext();
//实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//【4、刷新应用上下文前的准备阶段】
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//【5、刷新应用上下文】
refreshContext(context);
//【6、刷新应用上下文后的扩展接口】
afterRefresh(context, applicationArguments);
//时间记录停止
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//发布容器启动完成事件
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
在刷新应用上下文时,会调用Spring IOC容器的核心方法refresh进行对象创建等操作,而在refresh中在调用invokeBeanFactoryPostProcessors(beanFactory)即BeanFactory 的后处理器方法中:
1. 解析ComponsentScan 获取到要解析的包路径(配置未指定 basePackages、value
)扫描路径时,默认为注解所在类,会将主方法对应的包下所有的@Componsent注解的类信息封装到BeanDefiniction中,存放到beanDefinitionMap(IOC容器中)
2. 调用AutoConfigurationImportSelector 内部类 AutoConfigurationGroup的 process() 及 selectImports()方法.从所有META-INF下的spring.factories文件中根据key为EnableAutoConfiguration全路径类名的类信息。进行必要过滤后,最终过滤后的类信息生成对应的信息放入IOC容器中。