一句话总结:在context的refresh方法中,需要注册bean definition,实例化bean.在加载bean defintion的时候使用ConfigurationClassParser类来解析我们的主类。然后在解析主类的时候发现了@EnableAutoConfiguratio注解中的@Import注解,就去处理@Import注解中的value值,然后就使用ImportSelector来获取被配置在spring.factories中的类。这些类通常是AutoConfiguration。这些configuration中包含了各种各样的bean
一切的开始源于AppBootstrap.main
方法,它调用了SpringApplication.run(AppBootstrap.class)
方法。
在SpringApplication.run(AppBootstrap.class)方法中
-
//SpringApplication.java
-
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
-
return (
new SpringApplication(sources)).run(args);
-
}
所以我们可以看到spring启动流程大概分为两部,new和run。所以本篇文章会从分两个部分说明springboot的启动流程
。在诉说启动流程的过程中,会将spring boot 的自动配置
有关的东西重点拎出来。因为自动配置,我们可以什么都不做就可以启动一个web服务,不需要在web.xml中配置servlet,也不需要在applicationcontext.xml中配置componentScan。
new SpringApplication(sources)
-
public SpringApplication(Object... sources) {
-
//设置打印模式
-
this.bannerMode = Mode.CONSOLE;
-
this.logStartupInfo =
true;
-
this.addCommandLineProperties =
true;
-
this.headless =
true;
-
this.registerShutdownHook =
true;
-
this.additionalProfiles =
new HashSet();
-
//主要设置listeners,initializer。listeners监听env,context的事件。initializer是在prepareContext中用来初始化context
-
this.initialize(sources);
-
}
属性设置
headless 刑天模式
Headless模式是在缺少显示屏、键盘或者鼠标时的系统配置。
在java.awt.toolkit和java.awt.graphicsenvironment类中有许多方法,除了对字体、图形和打印的操作外还需要调用显示器、键盘和鼠标的方法。在电脑缺少对应硬件设备的时候会抛出HeadlessException异常。但是有些类,如Canvas也可以在headless下正常使用。
headless
headless
初始化
initialize(sources)
-
private void initialize(Object[] sources) {
-
if (sources !=
null && sources.length >
0) {
-
this.sources.addAll(Arrays.asList(sources));
-
}
-
/*deduceWebEnvironment方法通过判断
-
javax.servlet.Servlet,
-
org.springframework.web.context.ConfigurableWebApplicationContext
-
这两个Class是否存在判断是否是Web环境*/
-
this.webEnvironment =
this.deduceWebEnvironment();
-
this.setInitializers(
this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
-
this.setListeners(
this.getSpringFactoriesInstances(ApplicationListener.class));
-
//设置mainApplicationClass为AppBootstrap
-
this.mainApplicationClass =
this.deduceMainApplicationClass();
-
}
ApplicationContextInitializer
在setInitializer方法中被实例化的initializer有:
查看这些initializer的类图:
他们都实现了ApplicationContextInitializer。顾名思义,和上下文有关的初始化器。也就是说这些实例将在上下文初始化的时候prepareContext
被使用。
-
public
interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
-
void initialize(C var1);
-
}
ApplicationListener
在setListeners方法中被实例的话listener包含:
这些listener都实现了ApplicationListener接口。这个接口表示这个接口将监听对应的ApplicationEvent
事件
-
public
interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
-
void onApplicationEvent(E var1);
-
}
整理几个listener和其监听的事件如下:
listener | 事件 |
---|---|
ConfigFileApplicationListener | ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent |
AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent |
LoggingApplicationListener | ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent |
ClasspathLoggingApplicationListener | ApplicationEnvironmentPreparedEvent,ApplicationFailedEvent |
BackgroundPreinitializer | ApplicationEnvironmentPreparedEvent |
DelegatingApplicationListener | ApplicationEnvironmentPreparedEvent,** |
ParentContextCloserApplicationListener | ParentContextAvailableEvent |
ClearCachesApplicationListener | ContextRefreshedEvent |
FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent |
LiquibaseServiceLocatorApplicationListener | ApplicationStartingEvent |
整理这些对应关系的目的在于,在启动流程中,会出发许多ApplicationEvent。这时会调用对应的listener的onApplicationEvent方法。
这里是一种观察者模式。对于观察者模式,个人的理解为:被观察者持有观察者的引用,在发生某些事情的时候,调用观察者的方法即可
setInitailizers和setListeners方法
在setInitailizers和setListeners方法中都用到了getSpringFactoriesInstances
.代码如下
-
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
-
return
this.getSpringFactoriesInstances(type,
new Class[
0]);
-
}
-
-
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-
Set<String> names =
new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
-
List<T> instances =
this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
-
AnnotationAwareOrderComparator.sort(instances);
-
return instances;
-
}
在其中使用SpringFactoriesLoader
来根据type,classLoader从几个jar包之类的spring.factories中获取类名,之后实例化对应的类。代码如下:
-
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
-
String factoryClassName = factoryClass.getName();
-
-
try {
-
//会查找几个Spring的jar包中的META-INF/spring.factories文件。
-
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);
-
}
-
}
SpringFactoriesLoader会查找几个Spring的jar包中的META-INF/spring.factories文件。被查找的factories文件的内容大致如下:
# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener # Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
在本项目中,被查找的有:
- spring-boot
- spring-boot-autoconfigure
- spring-beans
- spring-boot-test
- spring-boot-test-autoconfigure
- spring-test
这些jar包都是被直接或者间接的被项目所依赖.
spring.factories文件的作用也就间接的实现了自动化配置。我们可以在项目下创建自己的spring.factories文件。来向spring boot启动流程中加入我们自己需要的东西。
现在回到SetListener和setInitializer方法。他们使用SpringFactoriesLoader从spring.factories文件中获取对应type的类名。然后实例化这些类。并将这些实例保存在springApplication的对应属性中。 private List<ApplicationContextInitializer<?>> initializers;
或者private List<ApplicationListener<?>> listeners;
由于listener和initializer的构造函数几乎为null。所以不用去关心他们在构造函数中做了什么。
run
-
public ConfigurableApplicationContext run(String... args) {
-
StopWatch stopWatch =
new StopWatch();
-
stopWatch.start();
-
//context,上下文,我们的重点对象
-
ConfigurableApplicationContext context =
null;
-
FailureAnalyzers analyzers =
null;
-
this.configureHeadlessProperty();
-
//new SpringApplicationRunListeners用它来统一管理listeners,在事件发生的时候调用他们
-
SpringApplicationRunListeners listeners =
this.getRunListeners(args);
-
listeners.starting();
//如果有监听器监听启动事件,则执行对应的动作
-
-
try {
-
//从命令行中读取参数作为propertySource,放入到这里,会加入到env中
-
ApplicationArguments applicationArguments =
new DefaultApplicationArguments(args);
-
//创建env,加载配置文件,系统的属性,profile文件,application.yml, 初始化日志系统
-
ConfigurableEnvironment environment =
this.prepareEnvironment(listeners, applicationArguments);
-
//打印banner
-
Banner printedBanner =
this.printBanner(environment);
-
//创建context
-
context =
this.createApplicationContext();
-
new FailureAnalyzers(context);
-
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
-
this.refreshContext(context);
-
this.afterRefresh(context, applicationArguments);
-
listeners.finished(context, (Throwable)
null);
-
stopWatch.stop();
-
if (
this.logStartupInfo) {
-
(
new StartupInfoLogger(
this.mainApplicationClass)).logStarted(
this.getApplicationLog(), stopWatch);
-
}
-
-
return context;
-
}
catch (Throwable var9) {
-
this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
-
throw
new IllegalStateException(var9);
-
}
-
}
获取运行时监听器监听运行时发生的事件:getRunListeners
SpringApplicationRunListeners listeners = this.getRunListeners(args);
首先看SpringApplicationRunListeners
类。类中包含了一个SpringApplicationRunListener
的集合.
-
class SpringApplicationRunListeners {
-
private
final Log log;
-
private
final List<SpringApplicationRunListener> listeners;
-
}
-
public
interface SpringApplicationRunListener {
-
void starting();
-
-
void environmentPrepared(ConfigurableEnvironment var1);
-
-
void contextPrepared(ConfigurableApplicationContext var1);
-
-
void contextLoaded(ConfigurableApplicationContext var1);
-
-
void finished(ConfigurableApplicationContext var1, Throwable var2);
-
}
也就是说
在run方法中构造了一个SpringRunApplicationListeners,其中包含多个SpringRunApplicationListener
,用来监听应用启动过程中的start,environmentPrepared,contextPrepared,contextLoaded,finished等事件。
SpringRunApplicationLinsteners中到底包含哪些RunListener呢?包含从spring.factories中实例化的。在这里,getSpringFactoroiesIntsances方法返回只包含一个实例的集合,这个实例是EventPublishingRunListener
-
private SpringApplicationRunListeners getRunListeners(String[] args) {
-
Class<?>[] types =
new Class[]{SpringApplication.class, String[].class};
-
return
new SpringApplicationRunListeners(logger,
this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types,
this, args));
-
}
下面看EventPublishingRunListener类。
-
public
class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
-
private
final SpringApplication application;
-
private
final String[] args;
-
private
final SimpleApplicationEventMulticaster initialMulticaster;
-
public EventPublishingRunListener(SpringApplication application, String[] args) {
-
//在这里,application即SpringApplication
-
this.application = application;
-
this.args = args;
-
this.initialMulticaster =
new SimpleApplicationEventMulticaster();
-
Iterator var3 = application.getListeners().iterator();
-
-
//在SpringApplication.initailize()方法中初始化的listeners被加入到EventPublishingRunListener里面的initialMulticaster中
-
while(var3.hasNext()) {
-
ApplicationListener<?> listener = (ApplicationListener)var3.next();
-
this.initialMulticaster.addApplicationListener(listener);
-
}
-
-
}
-
}
EventPublishingRunListener通过引用SimpleApplicationEventMulticaster
来完成事件的发布和ApplicationListener的管理。
接下来我们仔细看SimpleApplicationEventMulticaster这个类。
从SimpleApplicationEventMulticaster类的结构中可以看到multicaster使用ListenerRetriever来管理ApplicationListener。使用了retrieverCache:ConcurrentHashMap
广播ApplicationStartedEvent事件:listeners.starting()
在上一步使用SpringRunApplicationListeners将所有的listener管理起来后,开始传播start事件
-
//EventPublishingRunListener
-
public void starting() {
-
this.initialMulticaster.multicastEvent(
new ApplicationStartedEvent(
this.application,
this.args));
-
}
需要注意的是:
-
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
-
ResolvableType type = eventType !=
null ? eventType :
this.resolveDefaultEventType(event);
-
//在这一步getApplicationListeners(event,type)中,会从所有的listener中取出支持这个事件类型的listener,一个新的retriever会持有这些listener的引用作为value,另外以(event,source)作为key,存在retrieverCache中。
-
Iterator var4 =
this.getApplicationListeners(event, type).iterator();
-
-
while(var4.hasNext()) {
-
final ApplicationListener<?> listener = (ApplicationListener)var4.next();
-
Executor executor =
this.getTaskExecutor();
-
if (executor !=
null) {
-
executor.execute(
new Runnable() {
-
public void run() {
-
SimpleApplicationEventMulticaster.
this.invokeListener(listener, event);
-
}
-
});
-
}
else {
-
this.invokeListener(listener, event);
-
}
-
}
-
-
}
在listener.starting()这一部中,几个listener都没有做什么动作。
构造应用参数:new DefaultApplicationArguments(args)
创建DefaultApplicationArguments的作用是将参数存储在DefaultApplicationArguments的内部类Source中。
其中Source的类结构如图:
我们追寻Source的构造函数可以发现,使用SimpleCommandLineArgsParser来解析参数,将解析后的参数存到PropertySource
的source属性中。
这里由于没有什么参数,所以略过。
创建和准备环境:environment
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
-
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
-
//创建env,如果是web环境,则创建StandardServletEnvironment,如果不是StandardEnvironment
-
ConfigurableEnvironment environment =
this.getOrCreateEnvironment();
-
//配置env
-
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
-
-
//广播environment事件
-
listeners.environmentPrepared((ConfigurableEnvironment)environment);
-
if (!
this.webEnvironment) {
-
environment = (
new EnvironmentConverter(
this.getClassLoader())).convertToStandardEnvironmentIfNecessary((ConfigurableEnvironment)environment);
-
}
-
-
return (ConfigurableEnvironment)environment;
-
}
这段代码主要分为几个步骤:
1. 创建Env
2. 配置Env
3. 调用监听器广播ApplicationEnvironmentPreparedEvent事件
创建Env
-
private ConfigurableEnvironment getOrCreateEnvironment() {
-
if (
this.environment !=
null) {
-
return
this.environment;
-
}
else {
-
return (ConfigurableEnvironment)(
this.webEnvironment ?
new StandardServletEnvironment() :
new StandardEnvironment());
-
}
-
}
如果是Web环境,则创建StandardServletEnvironment,否则创建StandardEnvironment.
下面的代码是有关Environment
和ConfigurableEnvironment
接口.
我们可以从接口中看出Environment主要作用为:获取系统的环境和spring的profile文件中的内容,存储到PropertySource
中。
-
public
interface Environment extends PropertyResolver {
-
String[] getActiveProfiles();
-
-
String[] getDefaultProfiles();
-
-
boolean acceptsProfiles(String... var1);
-
}
-
public
interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
-
void setActiveProfiles(String... var1);
-
-
void addActiveProfile(String var1);
-
-
void setDefaultProfiles(String... var1);
-
-
MutablePropertySources getPropertySources();
-
-
Map<String, Object> getSystemEnvironment();
-
-
Map<String, Object> getSystemProperties();
-
-
void merge(ConfigurableEnvironment var1);
-
}
有关Env的类图:
在environment初始化之后,PropertySources
中包含的几个PropertySource
为4个:
1. servletContextInitParam
2. servletConfigInitParams
3. systemEnv
4. systemProperties
简单说下PropertySource
的结构
-
//代表了name/value属性对的资源。source可以任何一种封装了属性值得类型。可以是Properties,Map,ServletContext,ServletConfig
-
//一般都很少单独使用PropertySource,而是使用PropertySources
-
public
abstract
class PropertySource<T> {
-
protected
final Log logger;
-
protected
final String name;
-
protected
final T source;
-
}
-
//PropertySources中聚合了多个PropertySource,包含PropertyResolver的实现可以实现从PropertySource中搜索
-
public
interface PropertySources extends Iterable<PropertySource<?>> {
-
boolean contains(String var1);
-
PropertySource<?> get(String var1);
-
}
当和@Configuration一起工作时,@PropertySource注解可以方便得为当前环境加入配置文件
和PropertySource相关的类图:
配置env
-
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
-
this.configurePropertySources(environment, args);
-
this.configureProfiles(environment, args);
-
}
-
//这两个函数分别用来添加命令行参数的PropertySource和设置activeProfile。由于项目中没有这些则略过
广播ApplicationEnvironmentPreparedEvent事件
调用RunListener,广播ApplicationEnvironmentPreparedEvent事件。受到影响的listener列在下表
listener | 事件 |
---|---|
ConfigFileApplicationListener | ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent |
AnsiOutputApplicationListener | ApplicationEnvironmentPreparedEvent |
LoggingApplicationListener | ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent |
ClasspathLoggingApplicationListener | ApplicationEnvironmentPreparedEvent,ApplicationFailedEvent |
BackgroundPreinitializer | ApplicationEnvironmentPreparedEvent |
DelegatingApplicationListener | ApplicationEnvironmentPreparedEvent,** |
FileEncodingApplicationListener | ApplicationEnvironmentPreparedEvent |
加载配置文件:ConfigFileApplicationListener。注意application.proporties文件在这一步加载
-
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
-
//ConfigFileApplicationListener使用EnvironmentPostProcessor来处理environment
-
List<EnvironmentPostProcessor> postProcessors =
this.loadPostProcessors();
-
postProcessors.add(
this);
-
AnnotationAwareOrderComparator.sort(postProcessors);
-
Iterator var3 = postProcessors.iterator();
-
-
while(var3.hasNext()) {
-
EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next();
-
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
-
}
-
-
}
EnvironmentPostProcessor会在应用上下文刷新之前定制应用的环境。EnvironmentPostProcessor的实现类需要注册在META-INF/spring.factories文件中,并且用类的全路径名作为key。并且其实现类被鼓励实现Ordered
接口或者@Order
注解,Ordered接口和@Order的作用在于将容器内的bean排序。
EnvironmentPostProcessor从中所周知的路径中加载属性文件用来配置应用上下文的环境。默认情况是:从classpath:
,file:./
,classpath:config/
,file:./config/:
四个位置加载applicatin.properties
或者application.yml
。
我们可以将EnvironmentPostProcessor作为一个动态管理配置文件的接口。
EnvironmentPostProcessor的扩展
回到ConfigFileApplicationListener的onApplicationEnvironmentPreparedEvent方法,它获取所有的EnvironmentPostProcessor来postProcessEnvironment。
1. SpringApplicationJsonEnvironmentPostProcessor
从Env中现有的配置解析spring.application.json.如果有值,则向env中添加一个MapPropertySource。spring.applictaion.json的值可以通过命令行参数传递进来
2. CloudFoundryVcapEnvironmentPostProcessor
从已经存在的env中寻找到VCAP
3. ConfigFileApplicationListener
从配置路径中加载application.properties/yml/xml
Spring Boot允许针对不同的环境配置不同的配置参数,可以使用 properties文件、YAML 文件、环境变量或者命令行参数来修改应用的配置。你可以在代码中使用@Value
注解来获取配置参数的值
经过这一步加载过后env中包含的ProperytySource有:
- 命令行参数
- 来自SPRING_APPLICATION_JSON的属性
- java:comp/env 中的 JNDI 属性
- Java系统环境变量
- 操作系统环境变量
- RandomValuePropertySource,随机值,使用 random.* 来定义
- jar包外的 Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
- jar包内的Profile 配置文件,如 application-{profile}.properties 和 YAML 文件
- jar包外的Application 配置,如 application.properties 和 application.yml
- 文件jar 包内的Application 配置,如 application.properties 和application.yml 文件
- 在标有@Configuration 注解的类标有@PropertySource注解的
- 默认值,使用SpringApplication.setDefaultProperties 设置的
设置输出格式AnsiOutputApplicationListener
AnsiOutputApplicationListener 根据spring.output.ansi.enabled的值来配置AnsiOutput
完成日志系统的集成:LoggingApplicationListener
SpringBoot在这一步完成与日志系统的集成。项目中如果使用了spring boot starter则默认使用logback。我们可以使用自己需要用的日志。只需要将适当的库添加到classpath,便激活各种日志系统。在classpath根目录可以提供一个合适命名的配置文件来定制日志系统。我们不需要在application.properties中做额外的操作。
spring的日志管理,写的很赞的一篇 在ApplicationStartedEvent事件中,LoggingApplicationListener寻找合适的日志系统
在ApplicationEnvironmentPrepared事件中,LoggingApplicationListener寻找到配置文件并且初始化日志系统
加快应用初始化BackgroundPreinitializer
spring boot 为了加速应用的初始化,在后台线程提前初始化一些耗时的任务
-
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
-
try {
-
Thread thread =
new Thread(
new Runnable() {
-
public void run() {
-
this.runSafely(
new BackgroundPreinitializer.MessageConverterInitializer(
null));
-
this.runSafely(
new BackgroundPreinitializer.MBeanFactoryInitializer(
null));
-
this.runSafely(
new BackgroundPreinitializer.ValidationInitializer(
null));
-
this.runSafely(
new BackgroundPreinitializer.JacksonInitializer(
null));
-
this.runSafely(
new BackgroundPreinitializer.ConversionServiceInitializer(
null));
-
}
-
-
public void runSafely(Runnable runnable) {
-
try {
-
runnable.run();
-
}
catch (Throwable var3) {
-
;
-
}
-
-
}
-
},
"background-preinit");
-
thread.start();
-
}
catch (Exception var3) {
-
;
-
}
-
-
}
创建和准备环境这一步做的事情总结如下:
1. 加载配置文件
2. 初始化日志系统
3. 提前加载某些后台的进程。在这些进程中创建一些消息转换器等
打印Banner
Banners:持有多个Bannner,循环打印
PrintBanner:持有一个Banner,打印
Banner可以打印在Console,也可以打印到日志文件中。所以有不同的输出路径。print函数应该有一个参数为OutputStream,用来做不同的输出方式
感兴趣的是使用
AnsiOutput.toString(new Object[]{AnsiColor.GREEN, ” :: Spring Boot :: “, AnsiColor.DEFAULT, padding, AnsiStyle.FAINT, version})方法输出有颜色的
创建应用上下文 createApplicationContext
-
protected ConfigurableApplicationContext createApplicationContext() {
-
Class<?> contextClass =
this.applicationContextClass;
-
if (contextClass ==
null) {
-
try {
-
contextClass = Class.forName(
this.webEnvironment ?
"org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext" :
"org.springframework.context.annotation.AnnotationConfigApplicationContext");
-
}
catch (ClassNotFoundException var3) {
-
throw
new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
-
}
-
}
-
-
return (ConfigurableApplicationContext)BeanUtils.instantiate(contextClass);
-
}
如果当前是Web应用,则实例化AnnotationConfigEmbeddedWebApplicationContext
,否则实例化AnnotationConfigApplicationContext
;
想要了解ApplicationContext的实例化过程中都做了什么,必须了解其类结构。
ApplicationContext有关的类结构
作为一个Context,ApplicationContext被赋予了很多功能。
EnvironmentCapable,携带环境的
ApplicationEventPublisher:发布事件
SingletonBeanRegistry:注册单例bean
ListableBeanFactory:bean工厂
DefaultResourceLoader:加载资源
BeanDefinitionRegistry:注册bean定义
我们追寻其构造方法,发现分别在AbstractApplicationContext和GenericApplicationContext和AnnotationConfigEmbeddedWebApplicationContext三个类中有构造方法。
AbstractApplicationContext
1. 设置Log
2. 设置id和displayName
3. **初始化BeanFactoryPostProcessor的集合**
4. active,closed初始化
5. 初始化ApplicationListener的集合
6. 设置resourcePatternResolver
2. GenericApplicationContext
1. customClassLoader = false
2. refreshed = false
3. **beanFactory = new DefaultListableBeanFactory**
3. AnnotationConfigEmbeddedWebApplicationContext
1. **this.reader = new AnnotatedBeanDefinitionReader(this);**
2. **this.scanner = new ClassPathBeanDefinitionScanner(this);**
我们简单介绍context中几个比较重要的类
BeanFactoryPostProcessor
,DefaultListableBeanFactory
, AnnotatedBeanDefinitionReader
,ClassPathBeanDefinitionScanner
;
BeanFactoryPostProcessor
可以修改应用上下文的bean definition,以适应上下文底层bean工厂的属性
spring boot会给我们提供一些默认的PostProcessor
DefaultListableBeanFactory
BeanFactory
Bean容器的根接口。这个接口需要被含有许多bean definition(每一个bean definition有一个唯一的String名字来标识)的对象所实现。根据bean definition,bean容器会返回一个独立的实例或者一个共享的单例。具体返回哪种,需要根据bean 容器的配置。这里说的类型就是Scope
BeanFactory是应用组件的集中注册器。我们在使用中最好使用DI(push推配置)来通过构造器或者settter方法来配置对象。而不是使用任何的pull配置来配置对象,比如通过一个BeanFactory查找。Spring的DI是被BeanFactory及其子类来实现的。
和ListableBeanFactory相反的是,HierarachalBeanFactory会在查找parent factory。如果一个bean没有查找到,会查找parent factory。子层次中的beans可以覆盖父层次中的相同名字的bean.
Bean Factory的实现需要支持标准的bean 的生命周期。下面是全部的初始化方法和他们的排序。
BeanNameAware’s setBeanName
BeanClassLoaderAware’s setBeanClassLoader
BeanFactoryAware’s setBeanFactory
EnvironmentAware’s setEnvironment
EmbeddedValueResolverAware’s setEmbeddedValueResolver
ResourceLoaderAware’s setResourceLoader (only applicable when running in an application context)
ApplicationEventPublisherAware’s setApplicationEventPublisher (only applicable when running in an application context)
MessageSourceAware’s setMessageSource (only applicable when running in an application context)
ApplicationContextAware’s setApplicationContext (only applicable when running in an application context)
ServletContextAware’s setServletContext (only applicable when running in a web application context)
postProcessBeforeInitialization methods of BeanPostProcessors
InitializingBean’s afterPropertiesSet
a custom init-method definition
postProcessAfterInitialization methods of BeanPostProcessors
在一个bean fatcory被关闭的时候,需要执行的生命周期的方法是:
postProcessBeforeDestruction methods of DestructionAwareBeanPostProcessors
DisposableBean’s destroy
a custom destroy-method definitions. BeanDefinitionRegistry
注册bean definition的接口。通常有BeanFactories来实现。Spring 的bean definition Reader需要使用这个接口。众所周知的实现是DefaultListableBeanFactory 和GenericApplicationContext.
DefaultListableBeanFactory
ListableBeanFactory和BeanDefinitionRegistry的实现。基于bean definition的bean factory.典型的用法是在获取bean之前,注册所有的bean definition。因此 bean definition的查找实在本地的集合中通过预先构建的bean definition metedata进行,是一项轻松的操作。
可以被作为一个标准的bean factory,或者是一个自定义工厂的父类。特定类型的bean definition 格式的读取器是独立实现的,而不是作为bean factory的子类。比如 PropertiesBeanDefinitionReader和XmlBeanDefinitionReader
AnnotatedBeanDefinitionReader
顾名思义:读取注解的bean definition的定义。
在GenericWebApplicationContext中构造了它的一个实例。看一下他的构造函数。
-
public
class AnnotatedBeanDefinitionReader {
-
private
final BeanDefinitionRegistry registry;
//context本身
-
private BeanNameGenerator beanNameGenerator;
-
private ScopeMetadataResolver scopeMetadataResolver;
-
private ConditionEvaluator conditionEvaluator;
-
-
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
-
this(registry, getOrCreateEnvironment(registry));
-
}
-
-
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
-
//bean的名字生成器
-
this.beanNameGenerator =
new AnnotationBeanNameGenerator();
-
//用来解析scope元数据
-
this.scopeMetadataResolver =
new AnnotationScopeMetadataResolver();
-
Assert.notNull(registry,
"BeanDefinitionRegistry must not be null");
-
Assert.notNull(environment,
"Environment must not be null");
-
this.registry = registry;
//bean定义注册器,用来容纳bean definition
-
this.conditionEvaluator =
new ConditionEvaluator(registry, environment, (ResourceLoader)
null);
//用来判断是否需要跳过注解
-
-
//我们需要关注这一步。原因是它注册了一个 ConfigurationClassPostProcessor
-
AnnotationConfigUtils.registerAnnotationConfigProcessors(
this.registry);
-
}
-
}
我们可以看到AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);这个方法里面做了这几件事情:
1. 设置beanfactory的依赖比较器
2. 设置beanfactory的autowire候选解析器
3. 给beanfatory注册几个postprocessor的bean definition。
这几个PostProcessor中含有一个特别重要的ConfigurationClassPostProcessor
。就是这个类使用ConfigurationClassParser
完成了basepackage目录下的bean的扫描,并循环处理这些类(处理其中的内部类,methodbean,import,接口,importResource,ProportyResource类)。
-
//AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
-
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
-
registerAnnotationConfigProcessors(registry, (Object)
null);
-
}
-
-
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Object source) {
-
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
-
...
-
Set<BeanDefinitionHolder> beanDefs =
new LinkedHashSet(
4);
-
RootBeanDefinition def;
-
if (!registry.containsBeanDefinition(
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor")) {
-
//这里这里这里
-
def =
new RootBeanDefinition(ConfigurationClassPostProcessor.class);
-
def.setSource(source);
-
beanDefs.add(registerPostProcessor(registry, def,
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor"));
-
}
-
....
-
return beanDefs;
-
}
-
private static BeanDefinitionHolder registerPostProcessor(BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
-
definition.setRole(
2);
-
registry.registerBeanDefinition(beanName, definition);
-
return
new BeanDefinitionHolder(definition, beanName);
-
}
ClassPathBeanDefinitionScanner
同样,一个好的名字能够让人理解这个类的功能。
ClassPathBeanDefinitionScanner是一个bean definition的扫描器,可以扫描类路径下的候选的bean,并在给定的registry注册bean definition。
需要配置类型过滤器来发现候选bean。默认的filters包含@Component,@Repository,@Service,@Controller注解。同样支持Java EE 6’s的ManagedBean和JSR-330’s Named 的注解
-
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
-
this(registry,
true);
-
}
-
-
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
-
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
-
}
-
-
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
-
this(registry, useDefaultFilters, environment, registry
instanceof ResourceLoader ? (ResourceLoader)registry :
null);
-
}
-
-
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment, ResourceLoader resourceLoader) {
-
this.beanDefinitionDefaults =
new BeanDefinitionDefaults();
-
//beanName生成器
-
this.beanNameGenerator =
new AnnotationBeanNameGenerator();
-
//scope元数据解析器
-
this.scopeMetadataResolver =
new AnnotationScopeMetadataResolver();
-
this.includeAnnotationConfig =
true;
-
Assert.notNull(registry,
"BeanDefinitionRegistry must not be null");
-
this.registry = registry;
-
//是否使用默认的类型过滤器。如果是,则注册默认的类型过滤器。
-
if (useDefaultFilters) {
-
this.registerDefaultFilters();
-
}
-
-
this.setEnvironment(environment);
-
this.setResourceLoader(resourceLoader);
-
}
-
protected void registerDefaultFilters() {
-
this.includeFilters.add(
new AnnotationTypeFilter(Component.class));
-
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
-
-
try {
-
this.includeFilters.add(
new AnnotationTypeFilter(ClassUtils.forName(
"javax.annotation.ManagedBean", cl),
false));
-
this.logger.debug(
"JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
-
}
catch (ClassNotFoundException var4) {
-
;
-
}
-
-
try {
-
this.includeFilters.add(
new AnnotationTypeFilter(ClassUtils.forName(
"javax.inject.Named", cl),
false));
-
this.logger.debug(
"JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
-
}
catch (ClassNotFoundException var3) {
-
;
-
}
-
-
}
我们可以在BeanDefinitionDefaults发现一些东西。
-
public
class BeanDefinitionDefaults {
-
private
boolean lazyInit;
-
private
int dependencyCheck =
0;
-
private
int autowireMode =
0;
-
private String initMethodName;
-
private String destroyMethodName;
-
}
初始化过程
至此,context的初始化过程完毕。我们回顾一下context在构造函数中做了什么 AbstractApplicationContext
1. 设置Log
2. 设置id和displayName
3. 初始化BeanFactoryPostProcessor的集合
4. active,closed初始化
5. 初始化ApplicationListener的集合
6. 设置resourcePatternResolver GenericApplicationContext
1. customClassLoader = false
2. refreshed = false
3. beanFactory = new DefaultListableBeanFactory AnnotationConfigEmbeddedWebApplicationContext
1. this.reader = new AnnotatedBeanDefinitionReader(this);注册了几个BeanDefinition,最重要的是CongiurationClassPostProcessor的bean definition
2. this.scanner = new ClassPathBeanDefinitionScanner(this);设置了需要识别的注解的类型
失败分析器
准备上下文prepareContext
我们初始化之后的ApplicationContext是最原始的状态。需要配置之前创建好的Environment,SpringApplicationRunListeners,ApplicationArguments,Banner
-
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
-
context.setEnvironment(environment);
//设置env
-
this.postProcessApplicationContext(context);
//如果SpringApplication类的beanNameGenerator,resourceLoader不为null,则设置到context中去。
-
//使用initializer做些初始化的动作
-
//1. 调用用户配置的initializer的方法
-
//2. 设置context的Id
-
//3. context注册 ConfigurationWarningsPostProcessor用于检查错误的配置
-
//4. 向env中设置实际的端口
-
//5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor
-
//6. 设置ContextRefreshedEvent监听器,打印ConditionEvaluationReport日志
-
this.applyInitializers(context);
-
listeners.contextPrepared(context);
-
if (
this.logStartupInfo) {
-
this.logStartupInfo(context.getParent() ==
null);
-
this.logStartupProfileInfo(context);
-
}
-
-
context.getBeanFactory().registerSingleton(
"springApplicationArguments", applicationArguments);
-
if (printedBanner !=
null) {
-
context.getBeanFactory().registerSingleton(
"springBootBanner", printedBanner);
-
}
-
-
Set<Object> sources =
this.getSources();
-
Assert.notEmpty(sources,
"Sources must not be empty");
-
this.load(context, sources.toArray(
new Object[sources.size()]));
-
listeners.contextLoaded(context);
-
}
使用initializer初始化context
-
protected void applyInitializers(ConfigurableApplicationContext context) {
-
Iterator var2 =
this.getInitializers().iterator();
-
-
while(var2.hasNext()) {
-
ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
-
//获取initailizer的类型参数的类型
-
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
-
Assert.isInstanceOf(requiredType, context,
"Unable to call initializer.");
-
//使用initializer来初始化context
-
initializer.initialize(context);
-
}
-
-
}
initializer | 用途 |
---|---|
DelegatingApplicationContextInitializer | 从context中获取env,从中获取用户是否配置了context.initializer.classes类。如果配置了这些类,则初始化他们并调用对应的initialize方法 |
ContextIdApplicationContextInitializer | 从env中解析名字和端口号,最后两者组合,设置为applicationContext的Id.我们在context的构造函数中给context设置的id值是context.toString即org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2b43529a。这一步之后,Id值为application:9188 |
ConfigurationWarningsApplicationContextInitializer | 这个初始化器的作用在于向context中注册ConfigurationWarningsPostProcessor,用于检查错误的配置和报告错误 |
ServerPortInfoApplicationContextInitializer | ApplicationContextInitializer向env设置EmbeddedServletContainer服务器实际监听的端口。实现这个功能的方法是:向context添加一个ApplicationListener,监听EmbeddedServletContainerInitializedEvent事件。当事件到达时,设置env中的local.server.port为实际端口值 |
SharedMetadataReaderFactoryContextInitializer | |
AutoConfigurationReportLoggingInitializer | 向applicationContext添加ApplicationListener用来监听ContextRefreshedEvent或者ApplicationFailedEvent事件。当事件发生时,打印ConditionEvaluationReport日志到info级别,如果出错,则打印到debug级别 |
总的来说:applyInitializers的所作的事情:
1. 调用用户配置的initializer的方法
2. 设置context的Id
3. context注册 ConfigurationWarningsPostProcessor用于检查错误的配置
4. 向env中设置实际的端口
5. SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor
6. 设置ContextRefreshedEvent监听器,打印ConditionEvaluationReport日志
向listeners广播contextPrepared
EventPublishingSpringApplicationRunListener中什么都没有做
打印启动日志
-
if (
this.logStartupInfo) {
-
//使用StartupInfoLogger打印启动信息.StartUpInfoLogger可以打印应用的starting,started的信息
-
this.logStartupInfo(context.getParent() ==
null);
-
this.logStartupProfileInfo(context);
-
}
-
protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
-
Log log =
this.getApplicationLog();
-
if (log.isInfoEnabled()) {
-
String[] activeProfiles = context.getEnvironment().getActiveProfiles();
-
if (ObjectUtils.isEmpty(activeProfiles)) {
-
String[] defaultProfiles = context.getEnvironment().getDefaultProfiles();
-
log.info(
"No active profile set, falling back to default profiles: " + StringUtils.arrayToCommaDelimitedString(defaultProfiles));
-
}
else {
-
log.info(
"The following profiles are active: " + StringUtils.arrayToCommaDelimitedString(activeProfiles));
-
}
-
}
-
-
}
打印结果为
-
INFO [11:57:12.206][main][org.springframework.boot.StartupInfoLogger][48]:Starting AppBootstrap on candydeMacBook-Pro.local with PID 19129 (/Users/maoyanyule/IdeaProjects/movie-pressurer/provider/target/classes started by maoyanyule
in /Users/maoyanyule/IdeaProjects/movie-pressurer)
-
INFO [11:58:25.218][main][org.springframework.boot.SpringApplication][593]:No active profile
set, falling back to default profiles: default
注册两个两个单例bean
-
context.getBeanFactory().registerSingleton(
"springApplicationArguments", applicationArguments);
-
if (printedBanner !=
null) {
-
context.getBeanFactory().registerSingleton(
"springBootBanner", printedBanner);
-
}
此时context.singletonObject中有三个对象:
1. springApplicationArguments
2. springBootBanner
3. autoConfigurationReport
将source加载到context中
-
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();
-
}
创建BeanDefinitionLoader,加载bean definition
创建bean definition Loader
BeanDefinitionLoader
bean 定义加载器。考虑bean definition的几种方式。有注解和Xml类型,同时需要扫描主类所在的目录。所以应该有AnnotatedBeanDefinitionReader
,XmlBeanDefinitionReader
-
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
-
Assert.notNull(registry,
"Registry must not be null");
-
Assert.notEmpty(sources,
"Sources must not be empty");
-
this.sources = sources;
-
this.annotatedReader =
new AnnotatedBeanDefinitionReader(registry);
-
this.xmlReader =
new XmlBeanDefinitionReader(registry);
-
if (
this.isGroovyPresent()) {
-
this.groovyReader =
new GroovyBeanDefinitionReader(registry);
-
}
-
-
this.scanner =
new ClassPathBeanDefinitionScanner(registry);
-
this.scanner.addExcludeFilter(
new BeanDefinitionLoader.ClassExcludeFilter(sources));
-
}
AnnotatedBeanDefinitionReader,ClassPathBeanDefinitionScanner在前文已经解释过 XmlBeanDefinitionReader
加载XML文件,并委托BeanDefinitionDocumentReader读取Xml文件,BeanDefinitionDocumentReader会在给定的bean fatcory注册bean definition。
加载bean definition
调用BeanDefinitionLoader.load()方法
-
//循环加载所有的sources
-
public int load() {
-
int count =
0;
-
Object[] var2 =
this.sources;
//这里的sources只有主类一个
-
int var3 = var2.length;
-
-
for(
int var4 =
0; var4 < var3; ++var4) {
-
Object source = var2[var4];
-
count +=
this.load(source);
-
}
-
-
return count;
-
}
-
-
//根据不同的source类型使用不同的方法加载
-
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());
-
}
-
}
-
//因为source为主类,所以是这个方法
-
private int load(Class<?> source) {
-
if (
this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
-
BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
-
this.load(loader);
-
}
-
//如果source被component注解,则使用AnnotatedBeanDefinitionReader来注册source的bean definition
-
if (
this.isComponent(source)) {
-
this.annotatedReader.register(
new Class[]{source});
-
return
1;
-
}
else {
-
return
0;
-
}
-
}
我们来看AnnotatedBeanDefinitionReader是如何注册一个source 的bean definition的
-
public void register(Class... annotatedClasses) {
-
Class[] var2 = annotatedClasses;
-
int var3 = annotatedClasses.length;
-
-
for(
int var4 =
0; var4 < var3; ++var4) {
-
Class<?> annotatedClass = var2[var4];
-
this.registerBean(annotatedClass);
-
}
-
-
}
-
-
public void registerBean(Class<?> annotatedClass) {
-
this.registerBean(annotatedClass, (String)
null, (Class[])
null);
-
}
-
-
public void registerBean(Class<?> annotatedClass, Class... qualifiers) {
-
this.registerBean(annotatedClass, (String)
null, qualifiers);
-
}
-
//主要是在这里
-
public void registerBean(Class<?> annotatedClass, String name, Class... qualifiers) {
-
//获取一个Class的bean定义,初始获取的bean definition。
-
AnnotatedGenericBeanDefinition abd =
new AnnotatedGenericBeanDefinition(annotatedClass);
-
//判断是否应该跳过这次注册
-
if (!
this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
-
//从source的注解中获取作用域,并设置到bean definition中
-
ScopeMetadata scopeMetadata =
this.scopeMetadataResolver.resolveScopeMetadata(abd);
-
abd.setScope(scopeMetadata.getScopeName());
-
//获取bean的名字
-
String beanName = name !=
null ? name :
this.beanNameGenerator.generateBeanName(abd,
this.registry);
-
//处理bean definition中的一些属性
-
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
-
if (qualifiers !=
null) {
-
Class[] var7 = qualifiers;
-
int var8 = qualifiers.length;
-
-
for(
int var9 =
0; var9 < var8; ++var9) {
-
Class<? extends Annotation> qualifier = var7[var9];
-
if (Primary.class == qualifier) {
-
abd.setPrimary(
true);
-
}
else
if (Lazy.class == qualifier) {
-
abd.setLazyInit(
true);
-
}
else {
-
abd.addQualifier(
new AutowireCandidateQualifier(qualifier));
-
}
-
}
-
}
-
//BeanDefinitionHolder中含有beanName,bean definition
-
BeanDefinitionHolder definitionHolder =
new BeanDefinitionHolder(abd, beanName);
-
//将作用域作用在bean definition 上
-
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder,
this.registry);
-
//在context中注册bean definition
-
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder,
this.registry);
-
}
-
}
在这里涉及到了 bean definition 的注册。 BeanDefinition
的类图
我们从AbstaractBeanDefinition可以看出一些眼熟的东西:
-
public
abstract
class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
-
public
static
final String SCOPE_DEFAULT =
"";
-
//autowire类型,和AutowireCapableBeanFactory是对应的
-
public
static
final
int AUTOWIRE_NO =
0;
-
public
static
final
int AUTOWIRE_BY_NAME =
1;
-
public
static
final
int AUTOWIRE_BY_TYPE =
2;
-
public
static
final
int AUTOWIRE_CONSTRUCTOR =
3;
-
/** @deprecated */
-
@Deprecated
-
public
static
final
int AUTOWIRE_AUTODETECT =
4;
-
//dependency_check类型
-
public
static
final
int DEPENDENCY_CHECK_NONE =
0;
-
public
static
final
int DEPENDENCY_CHECK_OBJECTS =
1;
-
public
static
final
int DEPENDENCY_CHECK_SIMPLE =
2;
-
public
static
final
int DEPENDENCY_CHECK_ALL =
3;
-
public
static
final String INFER_METHOD =
"(inferred)";
-
//bean class
-
private
volatile Object beanClass;
-
private String scope;
-
private
boolean abstractFlag;
-
private
boolean lazyInit;
-
private
int autowireMode;
-
private
int dependencyCheck;
-
private String[] dependsOn;
-
private
boolean autowireCandidate;
-
private
boolean primary;
-
private
final Map<String, AutowireCandidateQualifier> qualifiers;
-
private
boolean nonPublicAccessAllowed;
-
private
boolean lenientConstructorResolution;
-
private String factoryBeanName;
-
private String factoryMethodName;
-
private ConstructorArgumentValues constructorArgumentValues;
-
private MutablePropertyValues propertyValues;
-
private MethodOverrides methodOverrides;
-
private String initMethodName;
-
private String destroyMethodName;
-
private
boolean enforceInitMethod;
-
private
boolean enforceDestroyMethod;
-
private
boolean synthetic;
-
private
int role;
-
private String description;
-
private Resource resource;
-
}
在这一步完成之后,context中包含了一个和主类有关的bean definition.
广播contextLoaded事件
-
public void contextLoaded(ConfigurableApplicationContext context) {
-
ApplicationListener listener;
-
//在spring boot initializ()方法中初始化的listeners直到这一步才被添加到context的listener中
-
for(Iterator var2 =
this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
-
listener = (ApplicationListener)var2.next();
-
//如果listener中需要context实例,则设置
-
if (listener
instanceof ApplicationContextAware) {
-
((ApplicationContextAware)listener).setApplicationContext(context);
-
}
-
}
-
//广播ApplicationPreparedEvent事件
-
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(
this.application,
this.args, context));
-
}
listener | 事件 |
---|---|
ConfigFileApplicationListener | ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent |
LoggingApplicationListener | ApplicationStartingEvent,ApplicationEnvironmentPreparedEvent,ApplicationPreparedEvent,ContextClosedEvent,ApplicationFailedEvent |
DelegatingApplicationListener | ApplicationEnvironmentPreparedEvent,** |
我们有三个listener关心ApplicationPreparedEvent事件 ConfigFileApplicationListener
向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor LoggingApplicationListener
向context中注册单例bean:springBootLoggingSystem DelegatingApplicationListener
继续想其他listeners广播事件
prepareContext回顾
- 调用用户配置的initializer的方法
- 设置context的Id
- context注册 ConfigurationWarningsPostProcessor用于检查错误的配置
- 向env中设置实际的端口
- SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor
- 设置ContextRefreshedEvent监听器,打印ConditionEvaluationReport日志
- 打印启动日志
- 注册固定的单例bean
- 加载主类的bean definition
- 向context中添加ConfigFileApplicationListener.PropertySourceOrderingPostProcessor
刷新context refreshContext
-
private void refreshContext(ConfigurableApplicationContext context) {
-
this.refresh(context);
-
if (
this.registerShutdownHook) {
-
try {
-
context.registerShutdownHook();
-
}
catch (AccessControlException var3) {
-
;
-
}
-
}
-
-
}
-
protected void refresh(ApplicationContext applicationContext) {
-
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
-
//最终调用了applicationContext的refresh()函数
-
((AbstractApplicationContext)applicationContext).refresh();
-
}
而查看applicationContext.refresh()方法时需要注意其继承结构。附上applicationContext的类图
-
//EmbeddedWebApplicationContext.java
-
public final void refresh() throws BeansException, IllegalStateException {
-
try {
-
super.refresh();
//调用的是AbstractApplicationContext
-
}
catch (RuntimeException var2) {
-
this.stopAndReleaseEmbeddedServletContainer();
-
throw var2;
-
}
-
}
-
//AbstractApplicationContext.java
-
public void refresh() throws BeansException, IllegalStateException {
-
Object var1 =
this.startupShutdownMonitor;
-
synchronized(
this.startupShutdownMonitor) {
-
//1. 清空scanner中的resource和metadataReader之间的对应关系
-
//2. 设置applicationcontext中的初始状态
-
//3. 打印启动日志
-
//4. 设置env中的servletContext和serveltConfig
-
//5. 验证是否缺失了必须配置的参数
-
this.prepareRefresh();
//
-
ConfigurableListableBeanFactory beanFactory =
this.obtainFreshBeanFactory();
-
this.prepareBeanFactory(beanFactory);
-
-
try {
-
this.postProcessBeanFactory(beanFactory);
-
this.invokeBeanFactoryPostProcessors(beanFactory);
-
this.registerBeanPostProcessors(beanFactory);
-
this.initMessageSource();
-
this.initApplicationEventMulticaster();
-
this.onRefresh();
-
this.registerListeners();
-
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();
-
}
-
-
}
-
}
为刷新context做准备: prepareRefresh()
-
//AnnotationConfigEmbeddedWebApplicationContext
-
protected void prepareRefresh() {
-
this.scanner.clearCache();
-
super.prepareRefresh();
//调用AbstractApplicationContext中的prepareRefresh();
-
}
应该记得在构造函数中创建的ClassPathBeanDefinitionScanner。
在ClassPathBeanDefinitionScanner持有了一个Map:Resource, MetadataReader metadataReaderCache,用来保存resource和metadataReader;
scanner.clearCache()即清空该map的元素
-
//AbstractApplicationContext.java
-
protected void prepareRefresh() {
-
this.startupDate = System.currentTimeMillis();
-
this.closed.set(
false);
//设置application状态
-
this.active.set(
true);
//设置application状态
-
if (
this.logger.isInfoEnabled()) {
-
this.logger.info(
"Refreshing " +
this);
-
}
-
-
this.initPropertySources();
//调用的是GenericApplicationContext中的方法
-
this.getEnvironment().validateRequiredProperties();
//检查是否缺失了必须配置的属性
-
this.earlyApplicationEvents =
new LinkedHashSet();
//初始化
-
}
- initPropertySources
-
//GenericApplicationContext.java
-
protected void initPropertySources() {
-
ConfigurableEnvironment env =
this.getEnvironment();
-
if (env
instanceof ConfigurableWebEnvironment) {
-
((ConfigurableWebEnvironment)env).initPropertySources(
this.servletContext, (ServletConfig)
null);
-
//使用这里的servletContext和servletConfig来替换env中的propertySources
-
}
-
-
}
- this.getEnvironment().validateRequiredProperties();
回顾env的类图。查看代码,可发现validateRequiredProperties是调用了AbstractProportyReslover.validateRequiredProperties()方法.作用是检查是否缺失了必须配置的属性
-
public void validateRequiredProperties() {
-
MissingRequiredPropertiesException ex =
new MissingRequiredPropertiesException();
-
Iterator var2 =
this.requiredProperties.iterator();
-
-
while(var2.hasNext()) {
-
String key = (String)var2.next();
-
if (
this.getProperty(key) ==
null) {
-
ex.addMissingRequiredProperty(key);
-
}
-
}
-
-
if (!ex.getMissingRequiredProperties().isEmpty()) {
-
throw ex;
-
}
-
}
回顾prepareRefresh()这一步的动作:
1. 清空scanner中的resource和metadataReader之间的对应关系
2. 设置applicationcontext中的初始状态
3. 打印启动日志
4. 设置env中的servletContext和serveltConfig
5. 验证是否缺失了必须配置的参数
获取bean factory
-
//AbstractApplicationContext
-
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
-
this.refreshBeanFactory();
//刷新bean factory
-
ConfigurableListableBeanFactory beanFactory =
this.getBeanFactory();
//获取beanFactory
-
if (
this.logger.isDebugEnabled()) {
-
this.logger.debug(
"Bean factory for " +
this.getDisplayName() +
": " + beanFactory);
-
}
-
-
return beanFactory;
-
}
-
//GenericApplicationContext.java
-
protected final void refreshBeanFactory() throws IllegalStateException {
-
if (!
this.refreshed.compareAndSet(
false,
true)) {
-
//bean factory值可以刷新一次
-
throw
new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
-
}
else {
-
//设置beanFactory的serializationId和向
-
//Map<String, Reference<DefaultListableBeanFactory>> serializableFactories添加serializationId, new WeakReference(this)
-
this.beanFactory.setSerializationId(
this.getId());
-
}