学习过springboot的都知道,在Springboot的main入口函数中调用SpringApplication.run(DemoApplication.class,args)函数便可以启用SpringBoot应用程序,跟踪一下SpringApplication源码可以发现,最终还是调用了SpringApplication的动态run函数。
下面以SpringBoot2.0.3.RELEASE为例简单分析一下运行过程。
SpringApplicatiton部分源码:
1 public static ConfigurableApplicationContext run(Class<?>[] primarySources,
2 String[] args) {
3 //创建springapplication对象,调用函数run(args)
4 return new SpringApplication(primarySources).run(args);
5 }
上面的源码可以发现还是先创建SpringApplication实例,再调用run方法
第一步 分析 SpringApplication构造函数
SpringApplication构造函数代码如下:
1 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
2 this.resourceLoader = resourceLoader;
3 Assert.notNull(primarySources, "PrimarySources must not be null");
4 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
5
6 //1:判断web环境
7 this.webApplicationType = deduceWebApplicationType();
8
9 //2:加载classpath下META-INF/spring.factories中配置的ApplicationContextInitializer
10 setInitializers((Collection) getSpringFactoriesInstances(
11 ApplicationContextInitializer.class));
12 //3:加载classpath下META-INF/spring.factories中配置的ApplicationListener
13
14 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
15 //4:推断main方法所在的类
16 this.mainApplicationClass = deduceMainApplicationClass();
17 }
具体逻辑分析:
- deduceWebApplicationType(), SpringApplication构造函数中首先初始化应用类型,根据加载相关类路径判断应用类型,具体逻辑如下:
1 private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
2 + "web.reactive.DispatcherHandler";
3
4 private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
5 + "web.servlet.DispatcherServlet";
6
7 private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
8 "org.springframework.web.context.ConfigurableWebApplicationContext" };
9
10
11
12 private WebApplicationType deduceWebApplicationType() {
13 //当类路径中存在REACTIVE_WEB_ENVIRONMENT_CLASS并且不存在MVC_WEB_ENVIRONMENT_CLASS时
14 if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
15 && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
16 return WebApplicationType.REACTIVE;
17 }
18 //当加载的类路径中不包含WEB_ENVIRONMENT_CLASSES中定义的任何一个类时,返回标准应用
19 for (String className : WEB_ENVIRONMENT_CLASSES) {
20 if (!ClassUtils.isPresent(className, null)) {22 return WebApplicationType.NONE;
23 }
24 }
25 //加载的类路径中包含了WEB_ENVIRONMENT_CLASSES中定义的所有类型则判断为web应用
26 return WebApplicationType.SERVLET;
27 }
2. setInitializers初始化属性initializers,加载classpath下META-INF/spring.factories中配置的ApplicationContextInitializer,此处getSpringFactoriesInstances方法入参type=ApplicationContextInitializer.class
1 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
2 Class<?>[] parameterTypes, Object... args) {
3 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
4 // Use names and ensure unique to protect against duplicates
5 // SpringFactoriesLoader.loadFactoryNames()方法将会从calssptah下的META-INF/spring.factories中读取key为//org.springframework.context.ApplicationContextInitializer的值,并以集合形式返回
6 Set<String> names = new LinkedHashSet<>(
7 SpringFactoriesLoader.loadFactoryNames(type, classLoader));
8 //根据返回names集合逐个实例化,也就是初始化各种ApplicationContextInitializer,这些Initializer实际是在Spring上下文ApplicationContext执行refresh前调用
9 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
10 classLoader, args, names);
11 AnnotationAwareOrderComparator.sort(instances);
12 return instances;
13 }
3. setListeners 初始化属性listeners,加载classpath下META-INF/spring.factories中配置的ApplicationListener,此处入参为getSpringFactoriesInstances方法入参type= ApplicationListener.class
1 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
2 Class<?>[] parameterTypes, Object... args) {
3 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
4 // Use names and ensure unique to protect against duplicates
5 // SpringFactoriesLoader.loadFactoryNames()方法将会从calssptah下的META-INF/spring.factories中读取key为//org.springframework.context.ApplicationListener的值,并以集合形式返回
6 Set<String> names = new LinkedHashSet<>(
7 SpringFactoriesLoader.loadFactoryNames(type, classLoader));
8 //根据配置,初始化各种ApplicationListener,作用是用来监听ApplicationEvent
9 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
10 classLoader, args, names);
11 AnnotationAwareOrderComparator.sort(instances);
12 return instances;
13 }
第二步 分析 SpringApplication中 run方法
SpringApplication的run方法代码如下:
1 public ConfigurableApplicationContext run(String... args) {
2 StopWatch stopWatch = new StopWatch();
3 stopWatch.start();
4 ConfigurableApplicationContext context = null;
5 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
6 //设置系统变量java.awt.headless
7 configureHeadlessProperty();
8 //1:加载classpath下面的META-INF/spring.factories SpringApplicationRunListener
9 SpringApplicationRunListeners listeners = getRunListeners(args);
10 //2:执行所有runlistener的starting方法,实际上发布一个【ApplicationStartingEvent】事件
11 listeners.starting();
12 try {
13 //3:实例化ApplicationArguments对象
14 ApplicationArguments applicationArguments = new DefaultApplicationArguments(
15 args);
16 //4: 创建Environment (web环境 or 标准环境)+配置Environment,主要是把run方法的参数配置到Environment 发布【ApplicationEnvironmentPreparedEvent】事件
17 ConfigurableEnvironment environment = prepareEnvironment(listeners,
18 applicationArguments);
19 configureIgnoreBeanInfo(environment);
20 //打印banner,SpringBoot启动时,控制台输出的一个歪歪扭扭的很不清楚的Spring几个大字母,也可以自定义,参考博客:http://majunwei.com/view/201708171646079868.html
21 Banner printedBanner = printBanner(environment);
22 //5: 根据不同environment实例化context
23 context = createApplicationContext();
24 // 异常处理
25 exceptionReporters = getSpringFactoriesInstances(
26 SpringBootExceptionReporter.class,
27 new Class[] { ConfigurableApplicationContext.class }, context);
28 //6: 上下文相关预处理 发布【ApplicationPreparedEvent】事件
29 prepareContext(context, environment, listeners, applicationArguments,
30 printedBanner);
31 //7: 执行context的refresh,并且调用context的registerShutdownHook方法
32 refreshContext(context);
33 //8:空方法
34 afterRefresh(context, applicationArguments);
35 stopWatch.stop();
36 if (this.logStartupInfo) {
37 new StartupInfoLogger(this.mainApplicationClass)
38 .logStarted(getApplicationLog(), stopWatch);
39 }
40 //9:执行所有runlisteners的started方法,发布【ApplicationStartedEvent】事件
41 listeners.started(context);
42 //10: 遍历执行CommandLineRunner和ApplicationRunner
43 //如果需要在SpringBoot应用启动后运行一些特殊的逻辑,可以通过实现ApplicationRunner或CommandLineRunner接口中的run方法,该自定义类的run方法会在此处统一调用
44 callRunners(context, applicationArguments);
45 }
46 catch (Throwable ex) {
47 handleRunFailure(context, ex, exceptionReporters, listeners);
48 throw new IllegalStateException(ex);
49 }
50
51 try {
52 listeners.running(context);
53 }
54 catch (Throwable ex) {
55 handleRunFailure(context, ex, exceptionReporters, null);
56 throw new IllegalStateException(ex);
57 }
58 return context;
59 }
具体分析:
1. getRunListeners(args) 加载各种SpringApplicationRunListener实例,内部实现也还是通过SpringFactoriesLoader.loadFactoryNames(type, classLoader))实现,加载META-INF/spring.factories中key为org.springframework.boot.SpringApplicationRunListener的值,生成对应实例。
2. listeners.starting() 执行所有SpringApplicationRunListener的stating方法,发布ApplicationStartedEvent事件,该事件被ApplicationListener类型的listener监听
3. 实例化ApplicationArguments对象
4 . 配置环境并发布ApplicationEnvironmentPreparedEvent事件
1 private ConfigurableEnvironment prepareEnvironment(
2 SpringApplicationRunListeners listeners,
3 ApplicationArguments applicationArguments) {
4 // Create and configure the environment
5 ConfigurableEnvironment environment = getOrCreateEnvironment();
6 //configureEnvironment配置properties和profiles
7 configureEnvironment(environment, applicationArguments.getSourceArgs());
8 // 执行EventPublishingRunListener发布ApplicationEnvironmentPreparedEvent事件,将会被ApplicationListener监听到
9 listeners.environmentPrepared(environment);
10 //
11 bindToSpringApplication(environment);
12 if (this.webApplicationType == WebApplicationType.NONE) {
13 environment = new EnvironmentConverter(getClassLoader())
14 .convertToStandardEnvironmentIfNecessary(environment);
15 }
16 ConfigurationPropertySources.attach(environment);
17 return environment;
18 }
备注:实际上载spring-boot-2.0.3.RELEASE.jar包中,可以发现spring.factories中只配置了一个RunListener: org.springframework.boot.context.event.EventPublishingRunListener
截取EventPublishingRunListener.java部分代码:
1 public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
2
3
4 public EventPublishingRunListener(SpringApplication application, String[] args) {
5 this.application = application;
6 this.args = args;
7 this.initialMulticaster = new SimpleApplicationEventMulticaster();
8 //将SpringApplication实例中的ApplicationListener类型的listeners添加到initialMulticaster,后续执行监听
9 for (ApplicationListener<?> listener : application.getListeners()) {
10 this.initialMulticaster.addApplicationListener(listener);
11 }
12 }
13
14 // 发布一个ApplicationEnvironmentPreparedEvent事件
15 @Override
16 public void environmentPrepared(ConfigurableEnvironment environment) {
17 //所有被添加到initialMulticaster中的listener都将监听ApplicationEnvironmentPreparedEvent事件
18 this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
19 this.application, this.args, environment));
20 }
21
22 }
5. 根据environment类型创建ApplicationContext
6. 上下文相关处理:
1 private void prepareContext(ConfigurableApplicationContext context,
2 ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
3 ApplicationArguments applicationArguments, Banner printedBanner) {
4 context.setEnvironment(environment);
5 //配置beanNameGenerator和资源加载器
6 postProcessApplicationContext(context);
7 //回调所有的ApplicationContextInitializer
8 applyInitializers(context);
9 //执行所有SpringApplicationRunListener的contextPrepared方法,触发事件,实际上EventPublishingRunListener中contextPrepared是一个空方法,什么都没执行
10 listeners.contextPrepared(context);
11 if (this.logStartupInfo) {
12 logStartupInfo(context.getParent() == null);
13 logStartupProfileInfo(context);
14 }
15
16 //向Spring容器注入springApplicationArguments和springBootBanner
17 // Add boot specific singleton beans
18 context.getBeanFactory().registerSingleton("springApplicationArguments",
19 applicationArguments);
20 if (printedBanner != null) {
21 context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
22 }
23
24 // Load the sources
25 Set<Object> sources = getAllSources();
26 Assert.notEmpty(sources, "Sources must not be empty");
27 load(context, sources.toArray(new Object[0]));
28 //执行所有SpringApplicationRunListener的contextLoaded方法,下面是EventPublishingRunListener中的contextLoaded
29 listeners.contextLoaded(context);
30 }
EventPublishingRunListener.java中contextLoaded方法具体实现
1 public void contextLoaded(ConfigurableApplicationContext context) {
2 for (ApplicationListener<?> listener : this.application.getListeners()) {
3 if (listener instanceof ApplicationContextAware) {
4 ((ApplicationContextAware) listener).setApplicationContext(context);
5 }
6 context.addApplicationListener(listener);
7 }
8 //触发ApplicationPreparedEvent事件,ApplicationListener负责监听
9 this.initialMulticaster.multicastEvent(
10 new ApplicationPreparedEvent(this.application, this.args, context));
11 }
7. 执行context的refresh,并且调用context的registerShutdownHook方法,refresh方法的具体逻辑分析可以参考:
8. afterRefresh空方法
9. 执行所有runlisteners的started方法,发布ApplicationStartedEvent事件
10. 遍历执行CommandLineRunner和ApplicationRunner
以上。