没有合适的资源?快使用搜索试试~ 我知道了~
资源详情
资源评论
资源推荐
Spring Boot 运行机制源码剖析
一、SpringBoot入口程序
SpringApplication运行
自定义SpringApplication
1. 通过SpringApplicationAPI调整
2. 通过SpringApplicationBuilderAPI 调整
二、SpringBoot准备阶段
当程序开始执行之后,会调用SpringApplication的构造方法,进行某些初始参数的设置
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringApplication.run(Application.class, args)
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
springApplication.setWebApplicationType(WebApplicationType.NONE);
springApplication.setAdditionalProfiles("prod");
springApplication.setHeadless(true);
new SpringApplicationBuilder(Application.class)
.bannerMode(Banner.Mode.CONSOLE)
.web(WebApplicationType.NONE)
.profiles("prod")
.headless(true) .run(args);
//创建一个新的实例,这个应用程序的上下文将要从指定的来源加载Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>...
primarySources) {
//资源初始化资源加载器,默认为null
this.resourceLoader = resourceLoader;
//断言主要加载资源类不能为 null,否则报错
Assert.notNull(primarySources, "PrimarySources must not be null");
//初始化主要加载资源类集合并去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
配置Spring Boot Bean源
Java 配置 Class 或 XML 上下文配置文件集合,用于 Spring Boot BeanDefinitionLoader 读取 ,并
且将配置源解析加载为Spring Bean 定义
数量:一个或多个以上
Java配置Class
用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如 @Configuration
。
//推断当前 WEB 应用类型,一共有三种:NONE,SERVLET,REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//设置应用上线文初始化器,从"META-INF/spring.factories"读取
ApplicationContextInitializer类的实例名称集合并去重,并进行set去重。(一共7个)
setInitializers((Collection)
getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合
并去重,并进行set去重。(一共11个)
setListeners((Collection)
getSpringFactoriesInstances(ApplicationListener.class));
//推断主入口应用类,通过当前调用栈,获取Main方法所在类,并赋值给mainApplicationClass
this.mainApplicationClass = deduceMainApplicationClass();
}
//加载关系
SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)
-------> ConfigurableApplicationContext run(String... args)
-------> prepareContext(ConfigurableApplicationContext context)
------->load(context, sources.toArray(new Object[0]));
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " +
StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
XML上下文配置文件
用于 Spring 传统配置驱动中的 XML 文件
判断当前应用类型
在上述构造方法中,有一个判断应用类型的方法,用来判断当前应用程序的类型:
Web Reactive: WebApplicationType.REACTIVE
Web Servlet: WebApplicationType.SERVLET
非 Web: WebApplicationType.NONE
static WebApplicationType deduceFromClasspath() {
//如果存在reactive环境类,并且不存在Servlet环境类(jersey、mvc),则推断当前环境为
REACTIVE
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) &&
!ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
//不存在Servlet相关类,则推断当前环境为NONE
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//默认推断当前环境为SERVLET
return WebApplicationType.SERVLET;
}
//WebApplicationType的类型
public enum WebApplicationType {
/**
* The application should not run as a web application and should not start
an
* embedded web server.
* 非web项目
*/
NONE,
/**
* The application should run as a servlet-based web application and should
start an
* embedded servlet web server.
* servlet web 项目
*/
SERVLET,
/**
* The application should run as a reactive web application and should start
an
* embedded reactive web server.
* 响应式 web 项目
*/
REACTIVE;
加载应用上下文初始器 (ApplicationContextInitializer)
利用 Spring 工厂加载机制,实例化 ApplicationContextInitializer 实现类,并排序对象集合。
实现
技术
实现类: org.springframework.core.io.support.SpringFactoriesLoader
配置资源: META-INF/spring.factories
排序: AnnotationAwareOrderComparator#sort
加载应用事件监听器(ApplicationListener)
利用 Spring 工厂加载机制,实例化 ApplicationListener 实现类,并排序对象集合
找到程序运行的主类(Main Class)
根据 Main 线程执行抛异常操作,获取堆栈判断实际的引导类
参考方法: org.springframework.boot.SpringApplication#deduceMainApplicationClass
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[]
parameterTypes, Object... args) {
/**
* 利用 Spring 工厂加载机制,实例化type相关类,并排序对象集合。
*/
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;
}
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
三、SpringBoot运行阶段
springboot启动的run方法,可以看到主要是各种运行环境的准备工作
}
return null;
}
public ConfigurableApplicationContext run(String... args) {
//1、创建并启动计时监控类
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//2、初始化应用上下文和异常报告集合
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>
();
//3、设置系统属性“java.awt.headless”的值,默认为true,用于运行headless服务器,进行简
单的图像处理,多用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设
置为true
configureHeadlessProperty();
//4、创建所有spring运行监听器并发布应用启动事件,简单说的话就是获取
SpringApplicationRunListener类型的实例(EventPublishingRunListener对象),并封装进
SpringApplicationRunListeners对象,然后返回这个SpringApplicationRunListeners对象。说
的再简单点,getRunListeners就是准备好了运行时监听器EventPublishingRunListener。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//5、初始化默认应用参数类
ApplicationArguments applicationArguments = new
DefaultApplicationArguments(args);
//6、根据运行监听器和应用参数来准备spring环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//将要忽略的bean的参数打开
configureIgnoreBeanInfo(environment);
//7、创建banner打印类
Banner printedBanner = printBanner(environment);
//8、创建应用上下文,可以理解为创建一个容器
context = createApplicationContext();
//9、准备异常报告器,用来支持报告关于启动的错误
exceptionReporters =
getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class },
context);
//10、准备应用上下文,该步骤包含一个非常关键的操作,将启动类注入容器,为后续开启自动化
提供基础
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//11、刷新应用上下文
refreshContext(context);
//12、应用上下文刷新后置处理,做一些扩展功能
afterRefresh(context, applicationArguments);
//13、停止计时监控类
stopWatch.stop();
剩余24页未读,继续阅读
kdbshi
- 粉丝: 55
- 资源: 300
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0