Spring Boot 启动原理
Springboot项目启动类:
1
2
3
4
5
6
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringBootApplication注解
@SpringBootApplication
注解是SpringBoot
的核心注解,它其实是一个组合注解:
1
2
3
4
5
6
7
8
9
10
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
Class<?>[] exclude() default {};
}
最重要的是:
@ComponentScan
@EnableAutoConfiguration
@Configuration
@Configuration
表达形式
任何一个标注了@Configuration
的Java类定义都是一个JavaConfig配置类。
基于XML配置
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<!--bean定义-->
</beans>
基于注解
1
2
3
4
@Configuration
public class DatasourceConfiguration{
//bean定义
}
注册bean定义
基于XML配置
1
2
3
<bean id="UserService" class="..UserServiceImpl">
...
</bean>
基于注解
任何一个标注了@Bean的方法,其返回值将作为一个bean定义注册到Spring的IoC容器,方法名将默认成该bean定义的id。
1
2
3
4
5
6
7
@Configuration
public class MockConfiguration{
@Bean
public UserService userService(){
return new UserServiceImpl();
}
}
表达依赖注入关系
基于XML配置
1
2
3
4
5
<bean id="userService" class="..UserServiceImpl">
<propery name ="dependencyService" ref="dependencyService" />
</bean>
<bean id="dependencyService" class="DependencyServiceImpl"></bean>
基于注解
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class MockConfiguration{
@Bean
public UserService userService(){
return new UserServiceImpl();
}
@Bean
public DependencyService dependencyService(){
return new DependencyServiceImpl();
}
}
@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。
@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。
@ComponentScan
@ComponentScan
的功能其实就是自动扫描并加载符合条件的组件(比如@Component
和@Repository
等)或者bean定义,最终将这些bean定义加载到IoC容器中。
通过basePackages
等属性来细粒度的定制@ComponentScan
自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan
所在类的package进行扫描。
所以SpringBoot
的启动类最好是放在root package下,因为默认不指定basePackages。
@EnableAutoConfiguration
@EnableAutoConfiguration
与@EnableScheduling
、@EnableCaching
、@EnableMBeanExport
等,@EnableAutoConfiguration
类似,借助@Import
的支持,收集和注册特定场景相关的bean定义。
@EnableScheduling
是通过@Import将Spring调度框架相关的bean定义都加载到IoC容器。@EnableMBeanExport
是通过@Import将JMX相关的bean定义加载到IoC容器。@EnableAutoConfiguration
也是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
@EnableAutoConfiguration
会根据类路径中的jar依赖为项目进行自动配置,如:添加了spring-boot-starter-web
依赖,会自动添加Tomcat和Spring MVC的依赖,Spring Boot会对Tomcat和Spring MVC进行自动配置。
1
2
3
4
5
6
7
8
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableAutoConfigurationImportSelector.class, Registrar.class})
public @interface EnableAutoConfiguration {
Class<?>[] exclude() default {};
}
@Import(EnableAutoConfigurationImportSelector.class)
,借助EnableAutoConfigurationImportSelector
,@EnableAutoConfiguration
可以帮助SpringBoot应用将所有符合条件的@Configuration
配置都加载到当前SpringBoot创建并使用的IoC容器。借助于Spring框架原有的一个工具类:SpringFactoriesLoader
的支持,@EnableAutoConfiguration
可以智能的自动配置。
SpringFactoriesLoader
SpringFactoriesLoader
属于Spring框架私有的一种扩展方案,其主要功能就是从指定的配置文件META-INF/spring.factories
加载配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public abstract class SpringFactoriesLoader {
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
//配置文件
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public SpringFactoriesLoader() {
}
//加载spring.factories,实例化对象,放入List返回
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
}
List<T> result = new ArrayList(factoryNames.size());
Iterator var5 = factoryNames.iterator();
while(var5.hasNext()) {
String factoryName = (String)var5.next();
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
//加载spring.factories里的类名,放到List里返回
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
//加载spring.factories的类生成Class实例,返回实例对象
private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader) {
try {
Class<?> instanceClass = ClassUtils.forName(instanceClassName, classLoader);
if (!factoryClass.isAssignableFrom(instanceClass)) {
throw new IllegalArgumentException("Class [" + instanceClassName + "] is not assignable to [" + factoryClass.getName() + "]");
} else {
return instanceClass.newInstance();
}
} catch (Throwable var4) {
throw new IllegalArgumentException("Cannot instantiate factory class: " + factoryClass.getName(), var4);
}
}
}
@EnableAutoConfiguration
自动配置:从classpath中搜寻所有的META-INF/spring.factories
配置文件,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration
对应的配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration
的JavaConfig形式的IoC容器配置类,然后汇总为一个并加载到IoC容器。
SpringApplication执行流程
SpringBoot的启动逻辑在SpringApplication这个类中,通过构造一个SpringApplication并调用run方法启动SpringBoot应用程序。SpringBoot启动后的主要流程:
-
设置webApplicationType(web应用类型);
webApplicationType是启动流程中一个比较重要的属性,SpringBoot根据它的类型来创建Environment对象和应用上下文对象(ApplicationContext)
-
准备应用上下文环境(Environment);
根据上一步推断的webApplicationType创建不同类型的Environment,并且将用户的profile文件读取到Environment中
- 读取profile;
-
创建并配置应用上下文对象(ApplicationContext)
根据webApplicationType创建不同实现的ApplicationContext
-
刷新应用上下文对象(refresh)
AbstractApplicationContext抽象类定义了上下文对象初始化核心流程,SpringBoot以BeanFactoryPostProcessor的方式实现包扫描、自动配置,将Bean预先加载成BeanDefinition后并实例化
-
后续处理
发布应用已启动事件并且调用容器中的Runner
源码
SpringApplication构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//启动
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//静态方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
//实例方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
//SpringApplication构造方法
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
//初始化方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//设置应用类型
this.webApplicationType =
WebApplicationType.deduceFromClasspath();
//查找并加载所有可用的ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//查找并加载所有可用的ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//推断并设置main方法的定义类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
SpringApplication.run(String… args)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
//查找并加载SpringApplicationRunListener调用starting()方法
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//根据webApplicationType创建不同类型的Environment,并且将用户的profile文件读取到Environment中
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//判断是否打印banner
Banner printedBanner = this.printBanner(environment);
//根据webApplicationType创建不同实现的ApplicationContext
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//遍历SpringApplicationRunListener,调用contextPrepared()的方法
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新应用上下文对象
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//遍历执行SpringApplicationRunListener的started()方法
listeners.started(context);
//查找当前ApplicationContext中ApplicationRunner和CommandLineRunner,遍历执行它们。
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
//遍历执行SpringApplicationRunListener的running()方法
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
一、设置应用类型
WebApplicationType.deduceFromClasspath()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
SpringBoot将应用程序分为三种类型:
- Reactive:Spring团队推出的Reactor编程模型的非阻塞异步Web编程框架WebFlux
- Servlet:基于J2EE Servlet API的编程模型,运行在Servlet容器上
- None:非Web应用程序 通过类路径中是否存在WebFlux中的Dispatcherhandler,SpringMVC中的DispatcherServlet、Servlet、ConfigurableWebApplicationContext来推断Web应用程序类型
二、准备应用上下文环境
SpringApplication.prepareEnvironment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
//创建环境对象
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//配置环境对象;主要是根据命令行参数配置profile
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
//发布应用环境已准备事件
listeners.environmentPrepared((ConfigurableEnvironment)environment);
//绑定spring.main属性到SpringApplication对象中
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
//如果用户设置的spring.main.web-application-type和spring推断的类型不一致,则使用用户设置的类型,创建对应的环境对象
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
//添加一个名为configurationProperties的PropertySource
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
-
创建Environment对象
在getOrCreateEnvironment方法中,会根据之前推断的webApplicationType(web程序类型)创建不同了实现的Environment对象
- 配置Environment对象
- 应用程序如果有命令行参数,则在Environment中添加一个与这个命令行参数相关的PropertySource
- 根据命令行参数中spring.profiles.active属性配置Environment对象中的activeProfile
-
发布ApplicationEnvironmentPreparedEvent(应用环境已准备)事件
SpringApplication发布完这个事件后,一个类型为ConfigFileApplicationListener的监听器会监听这个事件,它会去读取用户设置的profile文件(读取profile的详细流程在下一步中)
-
将Environment中的spring.main属性绑定到SpringAppilcation对象中
在执行到这一步时,Environment中已经包含了用户设置的profile文件属性
-
转换Environment对象的类型
在上一步中,如果用户使用spring.main.web-application-type属性手动设置了应用程序的webApplicationType并且用户设置的类型与SpringApplication推断出来的不一致,则SpringApplication会将环境对象转换成用户设置的webApplicationType相关的类型。
三、读取profile
在创建Environment对象前,SpringAppilcation已经将当前类路径jar包下所有spring.factories文件中的ApplicationListener加载并实例化完毕。
ApplicationListener:Spring Framework中的监听器接口,用来监听应用程序发布的事件
监听器列表中有一个类型为ConfigFileApplicationListener的监听器,当监听到ApplicationEnvironmentPreparedEvent事件时,它会从所有spring.factories中加载EnvironmentPostProcessor(环境后处理器)并执行他们的postProcessEnvironment方法(这个监听器本身也是一个环境后处理器,所以它也会执行自身的postProcessEnvironment方法,在这个方法中加载了用户设置的profile并以PropertySource的形式添加到Environment中)。
ConfigFileApplicationListener最终会构造一个Loader的内部类并调用Loader.load()方法加载profile;在Loader的构造函数中,会去加载所有spring.factories中的PropertySourceLoader,SpringBoot提供了两个PropertySourceLoader:
- PropertiesPropertySourceLoader(用来加载properties、xml文件)
- YamlPropertySourceLoader(用来加载yml、yaml文件)
SpringAppilcation.load(ApplicationContext context, Object[] sources)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
public int load() {
int count = 0;
Object[] var2 = this.sources;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
Object source = var2[var4];
count += this.load(source);
}
return count;
}
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class) {
return this.load((Class)source);
} else if (source instanceof Resource) {
return this.load((Resource)source);
} else if (source instanceof Package) {
return this.load((Package)source);
} else if (source instanceof CharSequence) {
return this.load((CharSequence)source);
} else {
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
}
Loader.load()加载profile的流程:
- 配置文件目录
- 配置文件名称
- 文件扩展名
profile属性生效的规则:
- 同名的profile:根据文件后缀优先级 properties > xml > yml > yaml;
- 被引用的profile:例一个profile中同时有spring.profiles.active和spring.profiles.include属性,则active的优先级 > include的优先级;
- 默认的profile优先级别最低;
- 如果把默认的profile当做第一级profile,在第一级profile中引用的profile(使用spring.profiles.active或者spring.profiles.include引用)当做下一级的profile,则下一级的profile(可能多个)优先级高于前一级的profile(一个),多个profile整体的优先级为第一级的profile优先级;例:
- application.yml内容:
- spring.profiles.active=p1,p2
-
spring.profiles.include=p3,p4
- application-p1.yml内容:
- spring.profiles.include=p5
则p2 > p1 > p4 > p3 > default 其中p5 > p1,结果是p2 > p5 > p1 > p4 > p3 > default
四、创建并配置应用上下文对象
ApplicationContext是Spring Framework中最核心的接口,用来表示一个应用的上下文;功能包括事件发布、国际化等,同时它也是一个BeanFactory。
SpringApplication通过webApplicationType的类型来创建不同的ApplicationContext,以SERVLET类型的webApplicationType为例,SpringApplication会创建类型为AnnotationConfigServletWebServerApplicationContext的上下文对象;
SpringApplication在prepareContext方法中对上下文对象进行预配置,主要做了:
-
执行所有ApplicationContextInitializer的initialize方法
这些ApplicationContextInitializer是在SpringApplication中的构造函数中加载的(通过读取spring.factories加载)
- 发布ApplicationContextInitializedEvent(上下文已初始化)事件
- 发布ApplicationPreparedEvent(上下文已准备)事件
五、刷新应用上下文
这里是ApplicationContext真正开始初始化容器和创建bean的阶段,其中bean的整个生命周期可以从这一步骤看出来;Spring Framework中的所有ApplicationContext实现都直接或间接继承自AbstracttApplicationContext,它的refresh方法描述了整个上下文的初始化逻辑。
源码:
SpringAppilcation.refreshContext(ConfigurableApplicationContext context)
1
2
3
4
5
6
7
8
9
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
SpringAppilcation.refresh(ApplicationContext applicationContext)
1
2
3
4
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
AbstractApplicationContext.refresh()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//准备更新上下文时的预备工作
this.prepareRefresh();
//获取上下文的内部BeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//对BeanFactory做些预备工作
this.prepareBeanFactory(beanFactory);
try {
//对BeanFactory进行预处理
this.postProcessBeanFactory(beanFactory);
//执行容器中的BeanFactoryPostProcessor
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册BeanPostProcessor
this.registerBeanPostProcessors(beanFactory);
//初始化MessageSource(国际化相关)
this.initMessageSource();
//初始化容器事件广播器(用来发布事件)
this.initApplicationEventMulticaster();
//初始化一些特殊的Bean
this.onRefresh();
//将所有监听器注册到前两步创建的事件广播器中
this.registerListeners();
//结束BeanFactory的初始化工作
this.finishBeanFactoryInitialization(beanFactory);
//上下文刷新完毕
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
流程:
- 准备更新上下文时的预备工作:
- 初始化PropertySource
- 验证Enrivonment中必要的属性
- 获取上下文的内部BeanFactory:内部BeanFactory的实现类是DefaultListableBeanFactory
- 对BeanFactory做些预备工作:
- 设置BeanFactory的Bean类加载器、Bean表达式解析器、属性编辑器注册表
- 添加类型为ApplicationContextAwareProcessor、ApplicationListenerDetector的BeanPostProcessor
- 让BeanFactory在自动装配时忽略一些接口类型
- 注册可解析的依赖(自动装配时碰到这些类型直接注入,包括BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext)
- 在BeanFactory中注册一些单例对象,包括environment、systemProperties、systemEnvironment
- 对BeanFactory进行预处理:
- 添加一个WebApplicationContextServletContextAwareProcessor的BeanPostProcessor
- 使BeanFactory自动装配时忽略ServletContextAware接口
- 在BeanFactory中注册request、session两种scope
- 注册可解析的依赖(自动装配时碰到这些类型可以注解注入,包括ServletRequest、ServletResponse、HttpSession、WebRequest)
- 执行容器中的BeanFactoryPostProcessor执行到这时容器已经注册了三个BeanFactoryPostProcessor,分别为:
- SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor:ApplicationContexttInitializer初始化时注册
- ConfigurationWarningsApplicationContextInitializer#ConfigurationWarningsPostProcessor:ApplicationContexttInitializer初始化时注册
- ConfigFileApplicationListener$PropertySourceOrderingPostProcessor
ApplicationPreparedEvent事件发布时由ConfigFileApplicationListener注册 BeanDefinitionRegistryPostProcessor是一种特殊的BeanFactoryPostProcessor,可以对BeanDefinition的注册表进行预处理
- 在BeanFactory中找到已注册的BeanFactoryPostProcessor,执行其中类型为BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
- 循环从BeanFactory中获取BeanDefinitionRegistryPostProcessor,从BeanDefinition注册表中获取,和上一步的来源不一样;有一个ConfigurationClassPostProcessor,ApplicationContext的构造函数中注册的
ConfigurationClassPostProcessor会执行SpringBoot的自动装配功能,将spring.factories中类型为EnableAutoConfiguration的类读取成BeanDefinition并过滤掉不满足条件的然后注册到BeanFactory中。
这一步骤会不断从BeanFactory中获取没有执行的BeanDefinitionRegistryPostProcessor并执行(可能用户会里面注册同类型的处理器)直到没有找到新的BeanDefinitionRegistryPostProcessor 包扫描、自动装配的功能都在ConfigurationClassPostProcessor中完成,执行完这一步后,所有Bean都会加载成BeanDefinition放入容器中 - 执行他们的postProcessBeanFactory方法对BeanFactory进行后处理
- 在BeanFactory中找到已注册的BeanFactoryPostProcessor,执行其中类型为BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法
- 注册BeanPostProcessor
BeanPostProcessor:Bean生命周期的钩子,允许用户对实例化后的Bean进行操作
- 从BeanFactory中获取所有BeanPostProcessor;
- 在BeanFactory中注册一个类型为BeanPostProcessorChecker的BeanPostProcessor;
- 将所有BeanPostProcessor按照实现了PriorityOrdered、Ordered、没有实现排序接口的顺序注册所有BeanPostProcessor到BeanFactory;
- 在BeanFactory中注册一个类型为ApplicationListenerDetector的BeanPostProcessor;
- 从BeanFactory中获取所有BeanPostProcessor;
- 初始化MessageSource(国际化相关)
- 初始化容器事件广播器(用来发布事件)
- 初始化一些特殊的Bean,主要做了:
- 初始化ThemeSource(跟国际化相关的接口)
- 创建WebServer
- 将所有监听器注册到前两步创建的事件广播器中
- 结束BeanFactory的初始化工作(这一步主要用来将所有的单例BeanDefinition实例化)
- 从BeanFactory中获取所有的BeanDefinition的beanName并遍历;
- 对Bean执行所有已注册的InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法(如果这个方法返回了一个Bean,Spring不会对这个Bean的属性进行注入,并且这个Bean的生命周期也会缺少几个步骤) PS:只要其中有一个方法的返回值不为null,则会立即返回这个Bean,这个Bean的生命周期和正常的Bean不同(Spring对这个类型的BeanPostProcessor的注释是让它有机会能返回一个代理对象);
- 实例化bean;
- 对Bean执行所有MergedBeanDefinitionPostProcessor.prostProcessMergedBeanDefinition(用来修改BeanDefinition的信息);
- 对Bean属性进行填充;
- 获取BeanFactory中所有InstantiationAwareBeanPostProcessor,对Bean执行postProcessAfterInstantiation方法(通常,这个方法应该返回true,如果返回false,后续的postProcessAfterInstantiation方法就不会执行了);
- 同上,获取所有InstantiationAwareBeanPostProcessor,对每一个InstantiationAwareBeanPostProcessor分两次调用;
- postProcessProperties,如果返回null,则继续调用下一步
- postProcessPropertyValues(返回的PropertyValues是最终使用的PropertyValues。如果这一步返回null,则不会执行后面的InstantiationAwareBeanPostProcessor)
- 如果上一步返回的PropertyValues有属性,则将属性应用到bean上
- 对实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware的接口进行接口调用;
- 对Bean执行BeanPostProcessor.postProcessBeforeInitialization方法;
- 对实现了InitializingBean的Bean调用接口方法,然后调用init-method(可以是@PostConstruct标注的方法);
- 对Bean执行PostProcessor.postProcessAfterInitialization方法;
- 如果Bean是一个SmartInitializingSingleton,则调用Bean的afterSingletonsInstantiated方法
- finishRefresh
- 初始LifecycleProcessor(生命周期处理器),向BeanFactory注册一个DefaultLifecycleProcessor;
- 调用LifecycleProcessor的onrefresh方法(找到所有已注册的SmartLifecycle,根据isRunning和isAutoStartup的条件判断,执行SmartLifecycle的start方法);
- 在ServletWebServerApplicationContetxt中,启动了WebServer并发布了ServletWebServerInitializedEvent事件;
六、后续处理
- 发布应用程序已启动(ApplicationStartedEvent)事件;
- 在BeanFactory中获取所有ApplicationRunner和CommandLineRunner并调用他们的run方法;