Springboot启动过程分析

释放双眼,带上耳机,听听看~!

Springboot启动过程分析

首先从一个入口程序开始


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
1@SpringBootApplication
2public class SpringLearnApplication {
3
4    public static void main(String[] args) {
5        System.out.println(SpringLearnApplication.class.getClassLoader());
6        //从这个run方法开始
7        SpringApplication.run(SpringLearnApplication.class, args);
8    }
9
10}
11
12public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
13      //这个方法分为两步,首先我们来看创建SpringApplication对象
14      return new SpringApplication(primarySources).run(args);
15  }
16 
17public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
18      this.resourceLoader = resourceLoader;
19      ...
20      this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
21      //推断应用类型,servlet还是reactor and so on
22      this.webApplicationType = WebApplicationType.deduceFromClasspath();
23      //实例化ApplicationContextInitializer接口的所有实现类
24      setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
25    //实例化ApplicationListener接口的所有实现类
26      setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
27    //推断主应用程序的fully qualified class name
28      this.mainApplicationClass = deduceMainApplicationClass();
29  }
30 //deduceMainApplicationClass()方法的核心代码:
31StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
32          for (StackTraceElement stackTraceElement : stackTrace) {
33              if ("main".equals(stackTraceElement.getMethodName())) {
34                  return Class.forName(stackTraceElement.getClassName());
35              }
36          }
37
38

加载spring factory


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1   private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
2       //用于存储从"META-INF/spring.factories"文件中加载的类的fully qualified class name
3       MultiValueMap<String, String> result = cache.get(classLoader);//第一次为空
4       if (result != null) {
5           return result;
6       }
7
8       try {
9           Enumeration<URL> urls = (classLoader != null ?
10                  classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
11                  ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
12          result = new LinkedMultiValueMap<>();
13          while (urls.hasMoreElements()) {
14              URL url = urls.nextElement();
15                //分别获取到beans,springboot,autoconfigture下面的META-INF/spring.factories文件路径
16              UrlResource resource = new UrlResource(url);
17              Properties properties = PropertiesLoaderUtils.loadProperties(resource);
18              for (Map.Entry<?, ?> entry : properties.entrySet()) {
19                  String factoryTypeName = ((String) entry.getKey()).trim();
20                  for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
21                        //把分别获从beans,springboot,autoconfigture下面获的META-INF/spring.factories文件中获取到的所有fully qualified class name添加到容器中,待后面的实例化
22                      result.add(factoryTypeName, factoryImplementationName.trim());
23                  }
24              }
25          }
26          cache.put(classLoader, result);
27          return result;
28      }
29      ...
30  }
31
32

第二步,启动程序


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
1public ConfigurableApplicationContext run(String... args) {
2       //该秒表用于计算程序执行的时间
3       StopWatch stopWatch = new StopWatch();
4       stopWatch.start();
5       ConfigurableApplicationContext context = null;
6       Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
7       //表示是一个运行于服务器的程序,没有键盘
8       configureHeadlessProperty();
9       //获取到所有实现SpringApplicationRunListener该接口的实现类的集合
10      SpringApplicationRunListeners listeners = getRunListeners(args);
11      //调用监听器starting()方法启动对应用的监听
12      listeners.starting();
13      try {
14          ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
15            //根据应用程序类型创建对应的环境,此处创建的是StandardServletEnvironment环境
16          ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
17          configureIgnoreBeanInfo(environment);
18            //打印Banner信息,默认为控制台输出spring标志及版本
19          Banner printedBanner = printBanner(environment);
20            //通过实例化AnnotationConfigServletWebServerApplicationContext创建上下文环境
21          context = createApplicationContext();
22            //实例化实现了SpringBootExceptionReporter该接口的所有类
23          exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
24                  new Class[] { ConfigurableApplicationContext.class }, context);
25          prepareContext(context, environment, listeners, applicationArguments, printedBanner);
26          refreshContext(context);
27          afterRefresh(context, applicationArguments);
28          stopWatch.stop();
29          if (this.logStartupInfo) {
30              new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
31          }
32          listeners.started(context);
33          callRunners(context, applicationArguments);
34      }
35      catch (Throwable ex) {
36          handleRunFailure(context, ex, exceptionReporters, listeners);
37          throw new IllegalStateException(ex);
38      }
39
40      try {
41          listeners.running(context);
42      }
43      catch (Throwable ex) {
44          handleRunFailure(context, ex, exceptionReporters, null);
45          throw new IllegalStateException(ex);
46      }
47      return context;
48  }
49
50

给TA打赏
共{{data.count}}人
人已打赏
安全技术

c++ list, vector, map, set 区别与用法比较

2022-1-11 12:36:11

安全网络

Zookeeper实现分布式锁

2021-8-18 16:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索