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中的推断实现
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.\r\n", 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(); }
来源:https://www.cnblogs.com/zhangpan1244/p/10595109.html