SpringApplication运行阶段
- 加载:SpringApplication 运行监听器
- 运行:SpringApplication 运行监听器
- 监听:Spring Boot事件、Spring事件
- 创建:应用上下文、Environment、其他
- 失败:故障分析报告
- 回调:CommandLineRunner、ApplicationRunner
具体:
(一)加载:SpringApplication 运行监听(SpringApplicationRunListeners)
利用 Spring 工厂加载机制,读取 SpringApplicationRunListener 对象集合,并且封装到组合类
SpringApplicationRunListeners
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
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;
}
说明:
1)getRunListeners(args);//运行监听器
可以看到工厂加载机制getSpringFactoriesInstances,把实例列表放进来了;
同时SpringApplicationRunListeners
这个对象在设计模式里称为组合对象
当在实现某个接口的时候通过foreach的方式执行。
SpringApplicationRunListeners里面有很多方法,都定义在SpringApplicationRunListener接口里
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
(二)运行:SpringApplication 运行监听器
SpringApplicationRunListener 监听多个运行状态方法:
- starting() : Spring 应用刚启动
- environmentPrepared(ConfigurableEnvironment) : ConfigurableEnvironment 准备妥当,允许将其调整
- contextPrepared(ConfigurableApplicationContext):ConfigurableApplicationContext 准备妥当,允许将其调整
- contextLoaded(ConfigurableApplicationContext):ConfigurableApplicationContext 已装载,但仍未启动
- started(ConfigurableApplicationContext): ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成
- running(ConfigurableApplicationContext) :Spring 应用正在运行
- failed(ConfigurableApplicationContext,Throwable) :Spring 应用运行失败
(三)监听:Spring Boot事件、Spring事件
Spring Boot 通过 SpringApplicationRunListener 的实现类 EventPublishingRunListener 利用 Spring Framework 事件
API ,广播 Spring Boot 事件。
spring.factories
EventPublishingRunListener是SpringApplicationRunListener唯一实现
它把接口都实现了一遍,从EventPublishingRunListener源码中看到都是和事件相关联
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener监听方法与SpringBoot事件对应关系
- starting() :ApplicationStartingEvent 1.5
- environmentPrepared(ConfigurableEnvironment):ApplicationEnvironmentPreparedEvent 1.0
- contextPrepared(ConfigurableApplicationContext)
- contextLoaded(ConfigurableApplicationContext): ApplicationPreparedEvent 1.0
- started(ConfigurableApplicationContext) ApplicationStartedEvent 2.0
- running(ConfigurableApplicationContext): ApplicationReadyEvent 2.0
- failed(ConfigurableApplicationContext,Throwable) :ApplicationFailedEvent 1.0
EventPublishingRunListener源码
有一个Multicaster广播器,会广播一个事件multicastEvent。
每个方法调用都会广播不同的事件如ApplicationStartingEvent、ApplicationEnvironmentPreparedEvent、ApplicationContextInitializedEvent、ApplicationPreparedEvent、ApplicationStartedEvent、ApplicationReadyEvent
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(
this.application, this.args, context));
}
……
SimpleApplicationEventMulticaster:简单事件应用广播器,这个广播器在不同的回调方法里做广播.
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
这些事件是Spring Framework 的事件扩展。
监听Spring事件
1、Spring Framework 事件/监听器编程模型
- Spring 应用事件
普通应用事件: ApplicationEvent 基类
应用上下文事件: ApplicationContextEvent- Spring 应用监听器
接口编程模型: ApplicationListener
注解编程模型: @EventListener- Spring 应用事广播器
接口: ApplicationEventMulticaster
实现类: SimpleApplicationEventMulticaster
执行模式:同步或异步
说明:
同步或异步
SimpleApplicationEventMulticaster 里面定义了taskExecutor(并发的时候,线程池的执行器)
在广播事件的时候multicastEvent,当线程池存在的时候,是异步去执行的
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
@Nullable
private ErrorHandler errorHandler;
……
public void setTaskExecutor(@Nullable Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
……
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
【栗子1----Spring Framework 事件/监听器】
在spring-application模块下新建一个SpringApplicationEventBootstrap类
(采用SpringFrameWork实现)
/**
* spring 应用事件引导类
*/
public class SpringApplicationEventBootstrap类 {
public static void main(String[] args) {
//创建上下文(注解驱动)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册应用事件监听器
context.addApplicationListener(event ->
System.out.println("监听到事件:" + event));
//启动上下文
context.refresh();
//发送事件
context.publishEvent("HelloWorld");
context.publishEvent("2019");
context.publishEvent(new ApplicationEvent("PK") {
});
//关闭上下文
context.close();
}
}
运行
1.png
说明:
1)publishEvent---这个接口是发了一个PayloadApplicationEvent事件
2)可以自定义事件
3)springboot实现也是类似的
【栗子2---实现SpringApplication运行监听器】
SpringApplicationRunListener是通过工厂机制加载的
(1)新建一个包run下面新建一个类HelloWorldRunListener,实现接口SpringApplicationRunListener,简单的实现第一个starting()
/**
* HelloWorld {@link SpringApplicationRunListener}
*/
public class HelloWorldRunListener implements SpringApplicationRunListener {
public HelloWorldRunListener(SpringApplication application, String[] args){
}
@Override
public void starting() {
System.out.println("HelloWorldRunListener.starting()...");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void started(ConfigurableApplicationContext context) {
}
@Override
public void running(ConfigurableApplicationContext context) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
注意:
EventPublishingRunListener有2个参数(SpringApplication application, String[] args)
如果你没有添加这2个参数,会报错:构造器没有这个方法:Caused by: java.lang.NoSuchMethodException: com.cbt.diveinspringboot.run.HelloWorldRunListener.<init>
我们看一下源码:
EventPublishingRunListener
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
在SpringApplication.java 里面传了二个参数this, args
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
getSpringFactoriesInstances,把所有的class都加载起来了,但是初始化的时候是根据构造器初始化的,同时将构造器里面的2个参数传进来
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
(2) 配置spring.factories
# SpringApplicationRunListener实现配置
org.springframework.boot.SpringApplicationRunListener=\
com.cbt.diveinspringboot.run.HelloWorldRunListener
(3)运行之前的引导类SpringApplicationBootstrap
在第一行就输出了
3.png
2、监听SpirngBoot事件
之前看EventPublishingRunListener类源码的时候,它是通过SpringApplicationRunListener回调的方式,发生不同的事件,产生不同效应。
在SpringApplication准备阶段的时候要加载ApplicationListener。
在本工程里spring.factories里面我们已经配置了相关Listener的实现。在构造阶段也已经将Listener装配好了。
当事件发送的时候会把application关联的listerner传进来,通过迭代的方式逐一去执行监听
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
再看一下SimpleApplicationEventMulticaster
实现里的发布事件的时候会迭代的完成。
getApplicationListeners会对事件加以区分
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
当我们不知道实现或者配置在spring工厂加载机制哪里实现的时候,借助IDEA工具find usages,看到非代码的配置(Non-code usages)
# 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.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
点击FileEncodingApplicationListener、LoggingApplicationListener上涉及的等等,可以看到他们关心的相关事件,以及顺序。
以上就是Spring Boot事件或者Spring事件应用的情况
特别要注意:监听事件是哪种事件以及顺序。
【栗子----监听SpringBoot事件】
先看一下ConfigFileApplicationListener源码
public class ConfigFileApplicationListener
implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
……
private int order = DEFAULT_ORDER;
……
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
……
}
说明:
1)ConfigFileApplicationListener关心2个事件,ApplicationEnvironmentPreparedEvent和ApplicationPreparedEvent,事件的执行顺序是ApplicationEnvironmentPreparedEvent是在ApplicationPreparedEvent前面的。
2)ApplicationEnvironmentPreparedEvent会读取application.properties文件。并且顺序要在DEFAULT_ORDER之前,也就是HIGHEST_PRECEDENCE + 10;(表示如果最大优先级第一个执行,它就是第11个执行,如果要比它优先的话+9)
具体操作:
(1)配置application.properties文件
name=PK
(2)在listener包下新建一个类BeforeConfigFileApplicationListener
/**
* Before {@link ConfigFileApplicationListener} 实现
*/
public class BeforeConfigFileApplicationListener implements SmartApplicationListener,Ordered {
@Override
public int getOrder() {
//比ConfigFileApplicationListener优先级更高
return ConfigFileApplicationListener.DEFAULT_ORDER +1;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return true;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent) event;
Environment environment = preparedEvent.getEnvironment();
System.out.println("environment.getProperty(\"name\") :" +environment.getProperty("name"));
}
if (event instanceof ApplicationPreparedEvent) {
}
}
说明:
1)实现接口Ordered和SmartApplicationListener
2)执行顺序,这里先采用比源码执行顺序靠前的顺序,所以运行的时候application.properties里的name是读不到的。
3)实现SmartApplicationListener接口的方法参照SmartApplicationListener的源码,进行修改。这里不处理2个事件了,通过PreparedEvent事件可以读到Environment来关联属性。
(3)将内容配置到spring.factories里(最后一个)
# Application Listeners 实现配置
org.springframework.context.ApplicationListener=\
com.cbt.diveinspringboot.listener.AfterHelloWorldApplicationListener,\
com.cbt.diveinspringboot.listener.HelloWorldApplicationListener,\
com.cbt.diveinspringboot.listener.BeforeConfigFileApplicationListener
(4)运行SpringApplicationBootstrap
name为null
4.png
当把执行顺序改为+1,在其之后执行
name就读取到了
要特别了解springboot的特性,优先级顺序
(四)创建:应用上下文( ConfigurableApplicationContext )
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableApplicationContext 实例:
- Web Reactive: AnnotationConfigReactiveWebServerApplicationContext
- Web Servlet: AnnotationConfigServletWebServerApplicationContext
- 非 Web: AnnotationConfigApplicationContext
创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment 实例:
- Web Reactive: StandardEnvironment
- Web Servlet: StandardServletEnvironment
- 非 Web: StandardEnvironment
在SpringApplication.run方法里有个createApplicationContext()
根据推断web类型,如果是
根据推断web类型,如果是
SERVLET---DEFAULT_SERVLET_WEB_CONTEXT_CLASS
REACTIVE-----DEFAULT_REACTIVE_WEB_CONTEXT_CLASS
default----DEFAULT_CONTEXT_CLASS
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
SpringApplication.java中的getOrCreateEnvironment()
当 SERVLET的时候就是StandardServletEnvironment,其他的时候就是StandardEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
在SpringApplication的run方法中也间接的表达了
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
再看run方法源码:
在starting的时候什么都没创建,后续开始创建一些,当Environment创建好了,会执行另外一个listener事件(environmentPrepared(environment)),那么ConfigurableEnvironment准备妥当,允许将其调整(参看之前运行SpringApplication运行监听器的监听方法)
然后会遇到createApplicationContext
然后contextPrepared调用就开始了
然后contextLoaded(context)事件开始了
等等,这些都是通过SpringApplication 上下文进行逐一调用的,伴随事件的产生,把相应的资源准备好
我们可以调整这个类型
【栗子】
模块下新建一个类SpringApplicationContextBootstrap
/**
* Spring应用上下文引导类
*/
@SpringBootApplication
public class SpringApplicationContextBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)
//.web(WebApplicationType.NONE) //非web类型
.run(args);
System.out.println("ConfigurableApplicationContext 类型:" +context.getClass().getName());
System.out.println("Environment 类型:" +context.getEnvironment().getClass().getName());
context.close();
}
}
运行:
1)推断出servlet,并且查看Environment类型的时候:
2)非web类型的话显示,并且查看Environment类型的时候:就是StandardEnvironment
8.png
3)换成REACTIVE会报错:没有jar包
终于完成了关于SpringApplication的相关学习,里面的东西还是需要结合源码再深度理解,把所有的东西串起来一下。
网友评论