- Document & Code
- Sping Application
- Customizing Spring Application
- Fluent Builder API
- Local Bootstrap Test
- Deduce Web Application Type
- Deduce Main Application Class
- Load Application Context Initializer
- Application Listeners
- Spring Application Run Listeners
- ConfigurableApplicationContext
SpingApplication 基本使用
- The
SpringApplication
class provides a convenient way to bootstrap a Spring application that is started from a main() method. In many situations, you can delegate to the staticSpringApplication.run
method, as shown in the following example:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
自定义 SpringApplication
- If the SpringApplication defaults are not to your taste, you can instead create a local instance and customize it. For example, to turn off the banner, you could write:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
流式构建
- If you need to build an
ApplicationContext
hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a “fluent” builder API, you can use theSpringApplicationBuilder
.- The
SpringApplicationBuilder
lets you chain together multiple method calls and includesparent
andchild
methods that let you create a hierarchy, as shown in the following example:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
本地启动测试
- 通过
SpringApplication.run(Class<?> primarySource, String... args)
指定本类为primarySource
参数。
package com.zozospider.springapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
- 通过
SpringApplication.run(Class<?> primarySource, String... args)
指定其他类为primarySource
参数 。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
public class SpringApplicationBootstrap2 {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfiguration.class, args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
- 通过
new SpringApplication().setSources(Set<String> sources)
指定其他类为Set<String> sources
参数 & 运行结果。
package com.zozospider.springapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.HashSet;
import java.util.Set;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
public class SpringApplicationBootstrap3 {
public static void main(String[] args) {
// 配置class名称
Set<String> sources = new HashSet();
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
// 运行并获取上下文
ConfigurableApplicationContext context = springApplication.run(args);
System.out.println("Bean: " + context.getBean(ApplicationConfiguration.class));
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
Bean: com.zozospider.springapplication.SpringApplicationBootstrap3$ApplicationConfiguration$$EnhancerBySpringCGLIB$$b75f6e8c@4d518b32
推断 Web 应用类型
SpringApplication
通过判断ClassPath
中是否存在相关实现类来推断 Web 应用的类型。类型如下:
- Web Reactive:
WebApplicationType.REACTIVE
- Web Servlet:
WebApplicationType.SERVLET
- 非 Web:
WebApplicationType.NONE
package org.springframework.boot;
...
public class SpringApplication {
...
// 初始化 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断 Web 应用类型
this.webApplicationType = deduceWebApplicationType();
// 加载应用上下文初始器 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 加载应用事件监听器 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断引导类(Main Class)
this.mainApplicationClass = deduceMainApplicationClass();
}
...
// 推断 Web 应用类型
private WebApplicationType deduceWebApplicationType() {
// 如果 org.springframework.web.reactive.DispatcherHandler 存在
// 且 org.springframework.web.servlet.DispatcherServlet 不存在
// 且 org.glassfish.jersey.server.ResourceConfig 不存在
// 则为 Web Reactive 类型
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
// 如果 javax.servlet.Servlet 不存在
// 且 org.springframework.web.context.ConfigurableWebApplicationContext 不存在
// 则为非 Web 类型
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 以上两个条件都不满足
// 则为 Web Servlet 类型
return WebApplicationType.SERVLET;
}
...
}
推断引导类(Main Class)
- 根据 Main 线程执行堆栈判断实际的引导类(通过异常堆栈信息判断是否存在
main
方法)。
package org.springframework.boot;
...
public class SpringApplication {
...
// 初始化 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断 Web 应用类型
this.webApplicationType = deduceWebApplicationType();
// 加载应用上下文初始器 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 加载应用事件监听器 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断引导类(Main Class)
this.mainApplicationClass = deduceMainApplicationClass();
}
...
// 推断引导类(Main Class)
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;
}
...
}
加载应用上下文初始器
ApplicationContextInitializer
- 利用 Spring 工厂加载机制,实例化
ApplicationContextInitializer
的具体实现类,并对具体实现类的执行顺序进行排序。
Spring Boot 举例
spring-boot-autoconfigure-2.0.5.RELEASE.jar!\META-INF\spring.factories
文件中配置ApplicationContextInitializer
的具体实现类。
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
- 利用 Spring 工厂加载
SpringFactoriesLoader
,实例化ApplicationContextInitializer
的具体实现类。
package org.springframework.boot;
...
public class SpringApplication {
...
// 初始化 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断 Web 应用类型
this.webApplicationType = deduceWebApplicationType();
// 加载应用上下文初始器 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 加载应用事件监听器 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断引导类(Main Class)
this.mainApplicationClass = deduceMainApplicationClass();
}
...
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
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;
}
...
}
package org.springframework.core.io.support;
...
public abstract class SpringFactoriesLoader {
// The location to look for factories(查找本地的 factories 文件)
// <p>Can be present in multiple JAR files.(包括 JAR 文件里的)
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
...
// 加载 factories 文件配置的具体实现类
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == 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());
for (String factoryName : factoryNames) {
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
// 对具体的实现类进行排序
AnnotationAwareOrderComparator.sort(result);
return result;
}
...
}
AnnotationAwareOrderComparator
对具体的实现类进行排序。判断方式如下:- 具体实现类是否实现
Ordered
接口- 具体实现类是否注解
@Order
如果存在则排序生效,否则按照默认规则排序。
package org.springframework.core.annotation;
...
public class AnnotationAwareOrderComparator extends OrderComparator {
...
@Override
@Nullable
protected Integer findOrder(Object obj) {
// Check for regular Ordered interface
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
return OrderUtils.getOrder((Class<?>) obj);
}
else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else {
order = OrderUtils.getOrder(obj.getClass());
if (order == null && obj instanceof DecoratingProxy) {
order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
}
return order;
}
...
}
自定义
- 新建
resources\META-INF\spring.factories
,指定ApplicationContextInitializer
实现的具体类。
# Initializers (copy from spring-boot-autoconfigure-2.0.5.RELEASE.jar!/META-INF/spring.factories)
org.springframework.context.ApplicationContextInitializer=\
com.zozospider.springapplication.context.FirstApplicationContextInitializer,\
com.zozospider.springapplication.context.SecondApplicationContextInitializer
- 创建
FirstApplicationContextInitializer
,实现ApplicationContextInitializer
接口,并注解Order
进行排序,指定为高级别。
package com.zozospider.springapplication.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
* FirstApplicationContextInitializer
*
* @param <C>
* @author zozo
* @since 1.0
*/
@Order(Ordered.HIGHEST_PRECEDENCE) // 进行排序,并指定为高级别
public class FirstApplicationContextInitializer<C extends ConfigurableApplicationContext>
implements ApplicationContextInitializer<C> {
@Override
public void initialize(C applicationContext) {
System.out.println("First ApplicationContextInitializer: " + applicationContext.getId());
}
}
- 创建
SecondApplicationContextInitializer
,实现ApplicationContextInitializer
接口和Ordered
接口,并重写Ordered
接口的getOrder()
方法,指定为低级别。
package com.zozospider.springapplication.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
/**
* SecondApplicationContextInitializer
*
* @author zozo
* @since 1.0
*/
public class SecondApplicationContextInitializer implements ApplicationContextInitializer, Ordered {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("Second ApplicationContextInitializer: " + applicationContext.getId());
}
/**
* 实现 Ordered 接口,进行排序,并指定为低级别
*
* @return
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
- 运行
SpringApplicationBootstrap
& 运行结果( web 和非 web 应用都可以)。
package com.zozospider.springapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
First ApplicationContextInitializer: org.springframework.context.annotation.AnnotationConfigApplicationContext@473b46c3
Second ApplicationContextInitializer: application
加载应用事件监听器
ApplicationListener
- 利用 Spring 工厂加载机制,实例化
ApplicationListener
的具体实现类,并对具体实现类的执行顺序进行排序。
Spring Boot 举例
spring-boot-autoconfigure-2.0.5.RELEASE.jar!\META-INF\spring.factories
和spring-boot-2.0.5.RELEASE.jar!/META-INF/spring.factories
文件中配置ApplicationListener
的具体实现类。
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# 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
- 利用 Spring 工厂加载
SpringFactoriesLoader
,实例化ApplicationListener
的具体实现类。
package org.springframework.boot;
...
public class SpringApplication {
...
// 初始化 SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断 Web 应用类型
this.webApplicationType = deduceWebApplicationType();
// 加载应用上下文初始器 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 加载应用事件监听器 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断引导类(Main Class)
this.mainApplicationClass = deduceMainApplicationClass();
}
...
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
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;
}
...
}
package org.springframework.core.io.support;
...
public abstract class SpringFactoriesLoader {
// The location to look for factories(查找本地的 factories 文件)
// <p>Can be present in multiple JAR files.(包括 JAR 文件里的)
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
...
// 加载 factories 文件配置的具体实现类
public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == 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());
for (String factoryName : factoryNames) {
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
// 对具体的实现类进行排序
AnnotationAwareOrderComparator.sort(result);
return result;
}
...
}
AnnotationAwareOrderComparator
对具体的实现类进行排序。判断方式如下:- 具体实现类是否实现
Ordered
接口- 具体实现类是否注解
@Order
如果存在则排序生效,否则按照默认规则排序。
package org.springframework.core.annotation;
...
public class AnnotationAwareOrderComparator extends OrderComparator {
...
@Override
@Nullable
protected Integer findOrder(Object obj) {
// Check for regular Ordered interface
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
// Check for @Order and @Priority on various kinds of elements
if (obj instanceof Class) {
return OrderUtils.getOrder((Class<?>) obj);
}
else if (obj instanceof Method) {
Order ann = AnnotationUtils.findAnnotation((Method) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else if (obj instanceof AnnotatedElement) {
Order ann = AnnotationUtils.getAnnotation((AnnotatedElement) obj, Order.class);
if (ann != null) {
return ann.value();
}
}
else {
order = OrderUtils.getOrder(obj.getClass());
if (order == null && obj instanceof DecoratingProxy) {
order = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
}
}
return order;
}
...
}
ApplicationListener
接口,定义实现类需要实现的方法。
package org.springframework.context;
...
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
BackgroundPreinitializer
和ConfigFileApplicationListener
等具体实现类实现ApplicationListener
接口,并指定排序。
package org.springframework.boot.autoconfigure;
...
@Order(LoggingApplicationListener.DEFAULT_ORDER + 1)
public class BackgroundPreinitializer
implements ApplicationListener<SpringApplicationEvent> {
@Override
public void onApplicationEvent(SpringApplicationEvent event) {
if (event instanceof ApplicationStartingEvent
&& preinitializationStarted.compareAndSet(false, true)) {
performPreinitialization();
}
if ((event instanceof ApplicationReadyEvent
|| event instanceof ApplicationFailedEvent)
&& preinitializationStarted.get()) {
try {
preinitializationComplete.await();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
...
}
package org.springframework.boot.context.config;
...
public class ConfigFileApplicationListener
implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
...
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
...
}
自定义
- 新建
resources\META-INF\spring.factories
,指定ApplicationListener
实现的具体类。
# Application Listeners (copy from spring-boot-autoconfigure-2.0.5.RELEASE.jar!/META-INF/spring.factories and spring-boot-2.0.5.RELEASE.jar!/META-INF/spring.factories)
org.springframework.context.ApplicationListener=\
com.zozospider.springapplication.listener.FirstApplicationListener,\
com.zozospider.springapplication.listener.SecondApplicationListener,\
com.zozospider.springapplication.listener.BeforeConfigFileApplicationListener,\
com.zozospider.springapplication.listener.AfterConfigFileApplicationListener
- 新建
resources/application.properties
,配置name
key 和对应的 value。
name = zozospider
- 创建
FirstApplicationListener
,实现ApplicationListener<ContextRefreshedEvent>
接口,并注解Order
进行排序,指定为高级别。
package com.zozospider.springapplication.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
* First {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
*
* @author zozo
* @since 1.0
*/
@Order(Ordered.HIGHEST_PRECEDENCE) // 进行排序,并指定为高级别
public class FirstApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("First ApplicationListener: " + event.getApplicationContext().getId()
+ ", timestamp: " + event.getTimestamp());
}
}
- 创建
SecondApplicationListener
,实现ApplicationListener<ContextRefreshedEvent>
接口和Ordered
接口,并重写Ordered
接口的getOrder()
方法,指定为低级别。
package com.zozospider.springapplication.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
/**
* Second {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
*
* @author zozo
* @since 1.0
*/
public class SecondApplicationListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("Second ApplicationListener: " + event.getApplicationContext().getId()
+ ", timestamp: " + event.getTimestamp());
}
/**
* 实现 Ordered 接口,进行排序,并指定为低级别
*
* @return
*/
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
- 创建
BeforeConfigFileApplicationListener
,实现ApplicationListener<ContextRefreshedEvent>
接口和Ordered
接口,并重写Ordered
接口的getOrder()
方法,指定为比ConfigFileApplicationListener
优先级更高。
package com.zozospider.springapplication.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.ConfigurableEnvironment;
/**
* Before {@link ConfigFileApplicationListener} 实现
*
* @zozo
* @since 1.0
*/
public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {
/**
* 参考 ConfigFileApplicationListener 实现
* @param eventType
* @return
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
/**
* 参考 ConfigFileApplicationListener 实现
* @param aClass
* @return
*/
@Override
public boolean supportsSourceType(Class<?> aClass) {
return true;
}
/**
* 参考 ConfigFileApplicationListener 实现,并试图获取 application.properties 中配置的 name 对应的值。
* @param event
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent) event;
ConfigurableEnvironment environment = preparedEvent.getEnvironment();
String name = environment.getProperty("name");
System.out.println("Before environment getProperty name: " + name);
}
if (event instanceof ApplicationPreparedEvent) {
}
}
/**
* 比 ConfigFileApplicationListener 优先级更高
*
* @return
*/
@Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
}
}
- 创建
AfterConfigFileApplicationListener
,实现ApplicationListener<ContextRefreshedEvent>
接口和Ordered
接口,并重写Ordered
接口的getOrder()
方法,指定为比ConfigFileApplicationListener
优先级更低。
package com.zozospider.springapplication.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.ConfigurableEnvironment;
/**
* After {@link ConfigFileApplicationListener} 实现
*
* @zozo
* @since 1.0
*/
public class AfterConfigFileApplicationListener implements SmartApplicationListener, Ordered {
/**
* 参考 ConfigFileApplicationListener 实现
* @param eventType
* @return
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
/**
* 参考 ConfigFileApplicationListener 实现
* @param aClass
* @return
*/
@Override
public boolean supportsSourceType(Class<?> aClass) {
return true;
}
/**
* 参考 ConfigFileApplicationListener 实现,并试图获取 application.properties 中配置的 name 对应的值。
* @param event
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent) event;
ConfigurableEnvironment environment = preparedEvent.getEnvironment();
String name = environment.getProperty("name");
System.out.println("After environment getProperty name: " + name);
}
if (event instanceof ApplicationPreparedEvent) {
}
}
/**
* 比 ConfigFileApplicationListener 优先级更低
*
* @return
*/
@Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
}
}
- 运行
SpringApplicationBootstrap
& 运行结果( web 和非 web 应用都可以)。
package com.zozospider.springapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
Before environment getProperty name: null
After environment getProperty name: zozospider
(以下两行为 Load Application Context Initializer 自定义运行结果)
First ApplicationContextInitializer: org.springframework.context.annotation.AnnotationConfigApplicationContext@75c072cb
Second ApplicationContextInitializer: application
First ApplicationListener: application, timestamp: 1539954515281
Second ApplicationListener: application, timestamp: 1539954515281
SpringApplication 运行监听器
Spring 框架运行监听器举例
package com.zozospider.springapplication;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Spring Framework 事件引导类
*
* @author zozo
* @since 1.0
*/
public class SpringFrameworkEventBootstrap {
public static void main(String[] args) {
// 创建上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注册应用事件监听器
context.addApplicationListener(event -> {
System.out.println("监听到事件: " + event);
});
// 启动上下文
context.refresh();
context.publishEvent("Hello Event 1");
context.publishEvent("Hello Event 2");
context.publishEvent(new ApplicationEvent("Hello Application Event") {
});
// 关闭上下文
context.close();
}
}
监听到事件: org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5f5a92bb: startup date [Sat Oct 20 14:26:38 CST 2018]; root of context hierarchy]
监听到事件: org.springframework.context.PayloadApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5f5a92bb: startup date [Sat Oct 20 14:26:38 CST 2018]; root of context hierarchy]
监听到事件: org.springframework.context.PayloadApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5f5a92bb: startup date [Sat Oct 20 14:26:38 CST 2018]; root of context hierarchy]
监听到事件: com.zozospider.springapplication.SpringFrameworkEventBootstrap$1[source=Hello Application Event]
监听到事件: org.springframework.context.event.ContextClosedEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@5f5a92bb: startup date [Sat Oct 20 14:26:38 CST 2018]; root of context hierarchy]
Spring Boot 运行监听器举例
spring-boot-2.0.5.RELEASE.jar!/META-INF/spring.factories
文件中配置SpringApplicationRunListener
的具体实现类。
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
- 利用 Spring 工厂加载
SpringFactoriesLoader
,实例化EventPublishingRunListener
的具体实现类。
SpringApplication
运行时调用SpringApplicationRunListeners
。
package org.springframework.boot;
...
public class SpringApplication {
...
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
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();
...
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
...
}
SpringApplicationRunListeners
装载所有实例化的SpringApplicationRunListener
,并统一调用。
package org.springframework.boot;
...
class SpringApplicationRunListeners {
...
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
...
}
SpringApplicationRunListener
接口,定义实现类需要实现的方法。
public interface SpringApplicationRunListener {
// Called immediately when the run method has first started. Can be used for very early initialization.
// Spring 应用刚启动
void starting();
// Called once the environment has been prepared, but before the {@link ApplicationContext} has been created.
// ConfigurableEnvironment 准备妥当,允许将其调整。
void environmentPrepared(ConfigurableEnvironment environment);
// Called once the {@link ApplicationContext} has been created and prepared, but before sources have been loaded.
// ConfigurableApplicationContext 准备妥当,允许将其调整
void contextPrepared(ConfigurableApplicationContext context);
// Called once the application context has been loaded but before it has been refreshed.
// ConfigurableApplicationContext 已装载,但仍未启动。
void contextLoaded(ConfigurableApplicationContext context);
// The context has been refreshed and the application has started but {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner ApplicationRunners} have not been called.
// ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成。
void started(ConfigurableApplicationContext context);
// Called immediately before the run method finishes, when the application context has been refreshed and all {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner ApplicationRunners} have been called.
// Spring 应用正在运行。
void running(ConfigurableApplicationContext context);
// Called when a failure occurs when running the application.
// Spring 应用运行失败。
void failed(ConfigurableApplicationContext context, Throwable exception);
}
EventPublishingRunListener
实现SpringApplicationRunListener
接口。
package org.springframework.boot.context.event;
...
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
...
@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));
}
...
}
Spring Boot 运行监听器自定义
- 新建
resources\META-INF\spring.factories
,指定SpringApplicationRunListener
实现的具体类。
# Run Listeners (copy from spring-boot-2.0.5.RELEASE.jar!/META-INF/spring.factories)
org.springframework.boot.SpringApplicationRunListener=\
com.zozospider.springapplication.run.HelloRunListener
- 创建
HelloRunListener
,实现SpringApplicationRunListener
接口。
package com.zozospider.springapplication.run;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Hello {@link SpringApplicationRunListener}
*
* @author zozo
* @since 1.0
*/
public class HelloRunListener implements SpringApplicationRunListener {
public HelloRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
System.out.println("HelloRunListener 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) {
}
}
- 运行
SpringApplicationBootstrap
& 运行结果( web 和非 web 应用都可以)。
package com.zozospider.springapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication} 引导类
*
* @author zozo
* @since 1.0
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
HelloRunListener starting()...
(以上四行为 Load Application Context Initializer 和 Application Listeners 自定义运行结果)
First ApplicationContextInitializer: org.springframework.context.annotation.AnnotationConfigApplicationContext@21507a04
Second ApplicationContextInitializer: application
First ApplicationListener: application, timestamp: 1540020038631
Second ApplicationListener: application, timestamp: 1540020038631
创建 Spring 应用上下文
根据准备阶段推断出的 Web 应用类型,创建对应的
ConfigurableApplicationContext
实例。
- Web Reactive:
AnnotationConfigReactiveWebServerApplicationContext
- Web Servlet:
AnnotationConfigServletWebServerApplicationContext
- 非 Web:
AnnotationConfigApplicationContext
根据准备阶段推断出的 Web 应用类型,创建对应的
ConfigurableEnvironment
实例。
- Web Reactive:
StandardEnvironment
- Web Servlet:
StandardServletEnvironment
- 非 Web:
StandardEnvironment
SpringApplication
运行时,根据 Web 应用类型,创建对应的ApplicationContext
package org.springframework.boot;
...
public class SpringApplication {
...
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);
// 根据 Web 应用类型,创建对应的 `ConfigurableEnvironment` 的实例
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
// 根据 Web 应用类型,创建对应的 `ConfigurableApplicationContext` 的实例
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;
}
...
// 根据 Web 应用类型,创建对应的 `ConfigurableEnvironment` 的实例
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
...
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();
}
}
...
// 根据 Web 应用类型,创建对应的 `ConfigurableApplicationContext` 的实例
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
// org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
case SERVLET:
contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
break;
// org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
// org.springframework.context.annotation.AnnotationConfigApplicationContext
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);
}
...
}
测试
package com.zozospider.springapplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
public class SpringApplicationContextBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
System.out.println("ConfigurableApplicationContext: " + context.getClass().getName());
System.out.println("ConfigurableApplicationContext getEnvironment: "+ context.getEnvironment().getClass().getName());
// 关闭上下文
context.close();
}
}
// 以下为 .web(WebApplicationType.NONE)
ConfigurableApplicationContext: org.springframework.context.annotation.AnnotationConfigApplicationContext
ConfigurableApplicationContext getEnvironment: org.springframework.core.env.StandardEnvironment