SpringApplication Explain
The
SpringApplication
class provides a convenient way to bootstrap a Spring application that is started from amain()
method. In many situations, you can delegate to the staticSpringApplication.run
method, as shown in the following example.(SpringApplication类提供了一种便利的方式以便引导Spring应用从
#main
启动,大多数情况下,可以通过静态方法SpringApplication#run
代理启动)
How TO Use SpringApplication
@EnableAutoConfiguration
public class MyApplication {
// ... Bean definitions
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
}
}
Customize SpringApplication
UseSpringApplication
API To Change
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
UseSpringApplicationBuilder
API To Change
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
SpringApplication Preparing Stage
Configure Spring Boot Bean's Sources
Java 配置类或XML上下文配置集合,用于Spring Boot BeanDefinitionLoader
读取,并且将配置源解析加载为Spring Bean 定义。
- 数量,一个或者多个
Java Configuration Class
使用Spring 注解驱动中的Java配置类,也就是Spring 模式注解所标注的类,例如@Configuration
package com.yi23.backend.springboot.bootstrap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 启动引导类
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
* @see
* @since
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class,args);
}
}
XML Configure
用户Spring 传统配置驱动的XML文件
...
//设置Annotation配置源
Set<String> sources = new HashSet<>();
//A source can be: a class name, package name, or an XML resource location.
sources.add(Yi23ApplicationConfiguration.class.getName());
springApplication.setSources(sources);
...
Deduce Web Application Type
根据当前应用CLassPath中是否存在相关实现来推断Web Application Type,包括:
- Web Reactive :
WebApplicationType.REACTIVE
- Web Servlet :
WebApplicationType.SERVLET
- 非Web :
WebApplicationType.NONE
参考:org.springframework.boot.SpringApplication#deduceWebApplicationType
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
- 版本意识,下图为Spring Boot 2.1.3中的推断实现
![image-20190306144854302](/Users/zhangpan/Library/Application Support/typora-user-images/image-20190306144854302.png)
Deduce Main Class
跟住main线程的执行堆栈判断当前实际的引导类
参考:org.springframework.boot.SpringApplication#deduceMainApplicationClass
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
Load ApplicationContextInitializer
ApplicationContextInitializer
是应用上下文的加载器,利用Spring 工厂加载机制,实例化ApplicationContextInitializer
实现类,并实现对象集合排序
- 代码
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// 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;
}
- 实现技术
- 实现类:
org.springframework.core.io.support.SpringFactoriesLoader
- 配置文件:
META-INF/spring.factories
- 排序:
org.springframework.core.annotation.AnnotationAwareOrderComparator#sort
- 实现类:
package com.yi23.backend.springboot.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
* 自定义高优先级{@link ApplicationContextInitializer}初始化加载器
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
* @see
* @since
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloYi23ApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("高优先级初始化加载class : "
+ applicationContext.getId());
}
}
# Initializers
org.springframework.context.ApplicationContextInitializer=
com.yi23.backend.springboot.context.AfterHelloYi23ApplicationContextInitializer,
com.yi23.backend.springboot.context.HelloYi23ApplicationContextInitializer
Load ApplicationListener
利用Spring 工厂加载机制,实例化ApplicationLisener
实现类,并实现对象集合排序
package com.yi23.backend.springboot.event.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
/**
* hello yi23 {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}事件
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
* @see
* @since
*/
public class HelloYi23ApplicationListener
implements ApplicationListener<ContextRefreshedEvent>,Ordered {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.printf("上下文内容id:%s,timestamp:%s.
",
event.getApplicationContext().getId(), event.getTimestamp());
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
SpringApplication Running Stage
Load SpringApplication
Run Listener
org.springframework.boot.SpringApplicationRunListeners
利用工厂加载机制,读取SpringApplicationRunListener
对象集合,并封装到组合对象SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
Running SpringApplication
Run Listeners
SpringApplicationRunListener
监听多个运行状态方法
监听方法 | 阶段说明 | Springboot 起始版本 |
---|---|---|
starting |
Spring 应用刚刚启动 | 1.0 |
environmentPrepared(ConfigurableEnvironment) |
ConfigurableEnvironment 准确之后,允许将其修改 |
1.0 |
contextPrepared(ConfigurableApplicationContext) |
ConfigurableApplicationContext 准备之后,允许将其修改 |
1.0 |
contextLoaded(ConfigurableApplicationContext) |
ConfigurableApplicationContext 已加载,但未启动 |
1.0 |
started(ConfigurableApplicationContext) |
ConfigurableApplicationContext 已启动,当前Spring Bean已初始化完成 |
2.0.0 |
running(ConfigurableApplicationContext) |
Spring Application 正在运行 | 2.0.0 |
failed(ConfigurableApplicationContex,Throwable) |
Spring Application运行失败 | 2.0.0 |
Monitor Spring-Boot Event / Spring Event
SpringBoot 通过SpringApplicationRunListener
的实现类EventPublishingRunListener
,利用Spring Framework事件API,广播Spring Boot 事件
Spring Framework Event/Listener Model
- Spring 应用事件
- 普通应用事件:
ApplicationEvent
- 应用上下文事件:
ApplicationContextEvent
- 普通应用事件:
- Spring 应用监听器
- 接口编程模型:
ApplicationListener
- 注解编程模型:
@EventListener
- 接口编程模型:
- Spring 应用事件广播器
- 接口:
ApplicationEventMulticaster
- 实现类:
SimpleApplicationEventMulticaster
- 执行模式:同步/异步
- 接口:
EventPublishingRunListener
relationship of Monitor‘s Method & Spring Boot Events
监听方法 | Spring Boot 事件 | Spring boot 起始版本 |
---|---|---|
starting |
ApplicationStartingEvent |
1.5.0 |
environmentPrepared(ConfigurableEnvironment) |
ApplicationEnvironmentPreparedEvent |
1.0 |
contextPrepared(ConfigurableApplicationContext) |
||
contextLoaded(ConfigurableApplicationContext) |
ApplicationPreparedEvent |
1.0 |
started(ConfigurableApplicationContext) |
ApplicationStartedEvent |
2.0.0 |
running(ConfigurableApplicationContext) |
ApplicationReadyEvent |
1.3.0 |
failed(ConfigurableApplicationContex,Throwable) |
ApplicationFailedEvent |
1.0 |
Validate ConfigFileApplicationListener
Order
package com.yi23.backend.springboot.event.listener;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
/**
* Before {@link ConfigFileApplicationListener}
*
* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a>
* @see
* @since
*/
public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public boolean supportsSourceType(Class<?> aClass) {
return true;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent) event;
Environment environment = environmentPreparedEvent.getEnvironment();
System.out.println("environment.getProperty("name"): " + environment.getProperty("name"));
}
if (event instanceof ApplicationPreparedEvent) {
}
}
@Override
public int getOrder() {
//比 ConfigFileApplicationListener 优先级高
return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
}
}
Create Spring Application Context(ConfigurableApplicationContext
)
根据前面提到的Prepared 阶段推断出的Web 应用类型对应的ConfigurableApplicationContext
实例:
- Web Reactive:
AnnotationConfigReactiveWebServerApplicationContext
- Web Servlet:
AnnotationConfigServletWebServerApplicationContext
- 非Web:
AnnotationConfigApplicationContext
/**
* Strategy method used to create the {@link ApplicationContext}. By default this
* method will respect any explicitly set application context or application context
* class before falling back to a suitable default.
* @return the application context (not yet refreshed)
* @see #setApplicationContextClass(Class)
*/
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_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);
}
Create Environment
根据Prepead 阶段推断的Web应用类型创建对应的 ConfigurableEnvironment
- Web Servlet:
StandardServletEnvironment
- Web Reactive:
StandardEnvironment
- 非Web:
StandardEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
if (this.webApplicationType == WebApplicationType.SERVLET) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}