SpringApplication 基本使用
SpringApplication 运行
SpringApplication.run(SpringBootApplication.class, args)
自定义 SpringApplication
通过 SpringApplication API 调整
SpringApplication springApplication = new SpringApplication(DiveInSpringBootApplication.class);
Set<String> sources = new HashSet<>();
sources.add(SpringbootdemoApplication.class.getName());
SpringApplication springApplication = new SpringApplication();
/**
* a class name, package name, or an XML resource location.
*/
springApplication.setSources(sources);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
springApplication.setWebApplicationType(WebApplicationType.NONE);
springApplication.setAdditionalProfiles("dev");
springApplication.setHeadless(true);
springApplication.run(args);
通过 SpringApplicationBuilder API 调整
new SpringApplicationBuilder(DiveInSpringBootApplication.class)
.bannerMode(Banner.Mode.CONSOLE)
.web(WebApplicationType.NONE)
.profiles("dev")
.headless(true)
.run(args);
springApplication准备阶段
SpringApplication构造阶段成为springApplication的准备阶段
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//配置spring的源
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断web类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//加载ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//加载ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断main Class
this.mainApplicationClass = deduceMainApplicationClass();
}
配置:spring Bean来源
Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并且将配置源解析加载为Spring Bean 定义
BeanDefinitionLoader
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);
//xml配置
this.xmlReader = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
Java 配置 Class
用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如 @Configuration 。
public class CalculateServiceBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(ApplicationBootstrap.class)
}
@SpringBootApplication
public static class ApplicationBootstrap{
}
}
@SpringBootApplication
public class CalculateServiceBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(CalculateServiceBootstrap.class)
}
}
XML 上下文配置文件
用于 Spring 传统配置驱动中的 XML 文件。
推断
推断 Web 应用类型
根据当前应用 ClassPath 中是否存在相关实现类来推断 Web 应用的类型,包括:
-
Web Reactive: WebApplicationType.REACTIVE
-
Web Servlet: WebApplicationType.SERVLET
-
非 Web: WebApplicationType.NONE
参考方法: org.springframework.boot.WebApplicationType#deduceFromClasspath
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
推断引导类(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;
}
###加载
加载应用上下文初始器 (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
- 排序: AnnotationAwareOrderComparator#sort
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
自定义ApplicationContextInitializer
@Order(Ordered.LOWEST_PRECEDENCE)
public class HelloWorldAfterApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext configure) {
System.out.println("configure after "+configure);
}
}
public class HelloWorldApplicationContextInitializer implements ApplicationContextInitializer,Ordered {
@Override
public void initialize(ConfigurableApplicationContext configure) {
System.out.println("configure "+configure);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
META-INF/spring.factories
# Initializers
org.springframework.context.ApplicationContextInitializer=\
cn.zhangspace.springbootdemo.context.HelloWorldApplicationContextInitializer,\
cn.zhangspace.springbootdemo.context.HelloWorldAfterApplicationContextInitializer
加载应用事件监听器( ApplicationListener )
利用 Spring 工厂加载机制,实例化 ApplicationListener 实现类,并排序对象集合
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
# 应用编码的ApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
# 关于配置文件的ApplicationListener
# application.properties adn/or application.yml
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
# 关于日志的ApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
ApplicationListener 主要关注两个方面
- Listener关注的事件
- Listener的优先级别
已LoggingApplicationListener为例
public class LoggingApplicationListener implements GenericApplicationListener {
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
}
spring boot-ApplicationListener 之order重要性
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 void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
String name = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment().getProperty("name");
System.out.println("配置文件name值为 "+name);
}
if (event instanceof ApplicationPreparedEvent) {
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 9;
}
}
META-INF/spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
cn.zhangspace.springbootdemo.listener.BeforeConfigFileApplicationListener
application.properties
name=zhangsan
输出结果为 null
修改BeforeConfigFileApplicationListener 中order
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 void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
String name = ((ApplicationEnvironmentPreparedEvent) event).getEnvironment().getProperty("name");
System.out.println("配置文件name值为 "+name);
}
if (event instanceof ApplicationPreparedEvent) {
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 11;
}
}
结果输出正确
spring boot 事件
SpringApplicationEvent
public abstract class SpringApplicationEvent extends ApplicationEvent {}
spring事件
ApplicationEvent
public abstract class ApplicationEvent extends EventObject {}
ApplicationContextEvent
public abstract class ApplicationContextEvent extends ApplicationEvent {}
- ApplicationEvent
- ApplicationContextEvent
- ContextClosedEvent
- ContextRefreshedEvent
- ContextStartedEvent
- ContextStoppedEvent
自定义事件监听器
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloworldContextRefreshedApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println(event.getApplicationContext().getBean("helloWorld"));
System.out.println("Hello word listener "+event.getApplicationContext().getId());
}
}
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HelloworldContextStartedEventApplicationListener implements ApplicationListener<ContextStartedEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("Hello word ContextStartedEvent listener "+event.getApplicationContext().getId());
}
}
META-INF/spring.factories
# Application Listeners
org.springframework.context.ApplicationListener=\
cn.zhangspace.springbootdemo.listener.HelloworldContextRefreshedApplicationListener,\
cn.zhangspace.springbootdemo.listener.HelloworldContextStartedEventApplicationListener