SpringBoot之SpringApplication Explain
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.\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();
}
SpringBoot之SpringApplication Explain的更多相关文章
- SpringBoot之SpringApplication
简介 可以用于从java主方法中引导和启动Spring应用程序的类,在默认情况下,通过以下步骤来启动应用: 创建一个ApplicationContext实例 注册CommandLineProperty ...
- springboot自定义SpringApplication启动类
如果默认的SpringApplication不符合你的口味,你可以创建一个本地的实例并自定义它.例如,关闭banner你可以这样写: public static void main(String[] ...
- 入门到熟练-SpringBoot
Spring Boot概述 1.1. Spring Boot是什么 Spring Boot是一套基于Spring框架的微服务框架. 1.2. Spring Boot框架出现的背景 由于Spring是一 ...
- [SpringBoot guides系列翻译]调度任务
原文 调度任务 用spring实现一个任务调度. 你将做的 你将做一个应用每5秒钟打印当前时间,用@Scheduled注解. 你需要啥 15分钟 文本编辑器或者IDE JDK1.8+ Gradle4+ ...
- Spring-boot简单的理解
SpringBoot启动 SpringApplication.run(MyBootApplication.class); SpringApplication.run启动SpringBoot应用,主要过 ...
- SpringBoot入门(1)
一.初始 ①.首先还是要创建一个maven工程 ②.然后编写Controller 让SpringBoot跑起来并不需要太多的代码,就能实现了我们平时要配置很多的功能,这是怎么做到的呢?我们就下面一个入 ...
- SpringBoot 入门 Demo
SpringBoot 入门 Demo Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从 ...
- idea实现第一个springboot程序
1.环境准备 JDK:1.8 Apache Maven: 3.6.1 IntelliJ IDEA 2019.1.3 x64 SpringBoot 1.5.9.RELEASE:1.5.9: 1.1.MA ...
- 自己动手实现springboot配置(非)中心
好久没写博客了,这段时间主要是各种充电,因为前面写的一些东西,可能大家不太感兴趣或者是嫌弃没啥技术含量,所以这次特意下了一番功夫.这篇博客其实我花了周末整整两天写好了第一个版本,已经开源出去了,同样是 ...
随机推荐
- 什么是DirectShow?
DirectShow是微软出的用于流媒体开发的开发包.开发语言是C++,没提供C#接口的调用方式.
- C#字符串类型
C#字符串类型(string)是一种引用类型,是System.String的别名,表示Unicode字符串. 两种表示方法: 1.“C#” 直接用双引号括起来. 2.使用@,@“c:\test”,可以 ...
- LINQ学习笔记(一)
LINQ,语言集成查询(Language Integrated Query)是一组用于C#和Visual Basic语言的扩展. 它允许编写C#或Visual Basic代码以查询数据库相同的方法操作 ...
- SharePoint Add-in Model (App Model) 介绍 – 概念、托管方式、开发语言
SharePoint Add-in Model 是自 2013 版本以来引入的新的扩展性开发模型, SharePoint 开发者可以利用这种新模型来实现往常利用场解决方案 (Farm Solution ...
- qt截获html请求(继承QNetworkAccessManager和QNetworkReply)
QtWebkit加载html页面,html中会有很多的请求,比如<img id="testImg" src="http://*.jpg" width=&q ...
- 使用spring容器干掉if-else
spring容器干掉if-else 场景说明 最近新做一个项目,需要对不同店铺的商品做不同处理.例如storeA需要进行handleA操作,storeB需要进行handleB操作,如此类推 大家很容易 ...
- sqlserver/mysql按天,按小时,按分钟统计连续时间段数据
文 | 子龙 有技术,有干货,有故事的斜杠青年 一,写在前面的话 最近公司需要按天,按小时查看数据,可以直观的看到时间段的数据峰值.接到需求,就开始疯狂百度搜索,但是搜索到的资料有很多都不清楚,需要自 ...
- RequestMappingHandlerAdapter和RequestParam原理分析
我们要使用定义了RequestMapping方法或者类是,需要先准备好所需要的参数.如何准备参数,我们应该考虑些上面问题. 都有哪些参数需要绑定? 除了方法确定的参数,还有两个方法的参数需要绑定,那就 ...
- spring源码深度解析— IOC 之 默认标签解析(上)
概述 接前两篇文章 spring源码深度解析—Spring的整体架构和环境搭建 和 spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签 ...
- ELK架构下利用Kafka Group实现Logstash的高可用
系统运维的过程中,每一个细节都值得我们关注 下图为我们的基本日志处理架构 所有日志由Rsyslog或者Filebeat收集,然后传输给Kafka,Logstash作为Consumer消费Kafka里边 ...