当前位置:   article > 正文

spring boot 2源码系列(一)- 系统初始化器ApplicationContextInitializer_implements applicationcontextinitializer

implements applicationcontextinitializer

《Spring Boot源码博客》

ApplicationContextInitializer接口的文档是这么写的:

1、ApplicationContextInitializer是一个回调接口,用于在ConfigurableApplicationContext#refresh()执行刷新之前初始化ConfigurableApplicationContext。SpringApplication#prepareContext()方法会执行ApplicationContextInitializer实现类的initialize方法。

2、通常在需要对应用程序上下文进行一些编程初始化的Web应用程序中使用,例如对ConfigurableApplicationContext#getEnvironment()注册属性源或者激活配置文件。

3、鼓励系统初始化器去实现org.springframework.core.Ordered Ordered接口或者使用@Order注解,以便在调用之前对实例进行排序。

若不举例说明,很难理解ApplicationContextInitializer接口的文档说的是什么意思。那现在就开始介绍系统初始化器的3种使用方式吧。

第一种:使用spring.factories配置

1、新建FirstInitializer实现ApplicationContextInitializer接口

  1. /**
  2. * 使用@Order注解(第3点)
  3. */
  4. @Order(1)
  5. public class FirstInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  6. /**
  7. * 在resources目录下新建/META-INF/spring.factories目录与文件。
  8. * 在resources/META-INF/spring.factories配置:
  9. * org.springframework.context.ApplicationContextInitializer=com.example.springbootdemo.FirstInitializer
  10. *
  11. * spring.factories的配置规则是: 接口全名=实现类全名
  12. */
  13. @Override
  14. public void initialize(ConfigurableApplicationContext applicationContext) {
  15. /**
  16. * 本方法代码是添加属性 key1=value1。
  17. *
  18. * 可通过以下方式获取添加的属性:
  19. * @Value("${key1}")
  20. * String key1;
  21. */
  22. ConfigurableEnvironment environment = applicationContext.getEnvironment();
  23. Map<String, Object> map = new HashMap<>();
  24. map.put("key1", "value1");
  25. // 新建属性源,并添加属性源。(第2点)
  26. MapPropertySource mps = new MapPropertySource("firstInitializer", map);
  27. environment.getPropertySources().addLast(mps);
  28. System.out.println("#############FirstInitializer.initialize 运行");
  29. }
  30. }

2、在resources目录下新建/META-INF/spring.factories目录与文件

在spring.factories中添加

org.springframework.context.ApplicationContextInitializer=com.example.springbootdemo.FirstInitializer

3、获取属性值的方式如下:

@Value("${key1}")
String key1;

4、启动工程,就能获取值了。

5、不使用@Order,通过实现Ordered接口实现排序。新建FirstOrderedInitializer.java

  1. /**
  2. * 通过实现Ordered接口实现排序
  3. */
  4. public class FirstOrderedInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
  5. @Override
  6. public void initialize(ConfigurableApplicationContext applicationContext) {
  7. System.out.println("#############FirstOrderedInitializer.initialize 运行");
  8. }
  9. // 返回排序值
  10. @Override
  11. public int getOrder() {
  12. return 11;
  13. }
  14. }

6、在spring.factories中添加

org.springframework.context.ApplicationContextInitializer=com.example.springbootdemo.FirstInitializer,\
com.example.springbootdemo.FirstOrderedInitializer

7、运行程序,控制台输出

#############FirstInitializer.initialize 运行
#############FirstOrderedInitializer.initialize 运行

FirstInitializer使用@Order注解排序值是1,FirstOrderedInitializer#getOrder()返回11。由此可知:排序值越小越先执行。

第二种:硬编码方式 addInitializers(new SecondInitializer());

1、新建SecondInitializer.java

  1. @Order(2)
  2. public class SecondInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  3. @Override
  4. public void initialize(ConfigurableApplicationContext applicationContext) {
  5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
  6. Map<String, Object> map = new HashMap<>();
  7. map.put("key2", "value2");
  8. MapPropertySource mps = new MapPropertySource("secondInitializer", map);
  9. environment.getPropertySources().addLast(mps);
  10. System.out.println("#############SecondInitializer.initialize 运行");
  11. }
  12. }

2、修改启动类,通过代码添加SecondInitializer

  1. @SpringBootApplication
  2. public class SpringBootDemoApplication {
  3. public static void main(String[] args) {
  4. //SpringApplication.run(SpringBootDemoApplication.class, args);
  5. // 第2中添加系统初始化器的方式
  6. SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
  7. springApplication.addInitializers(new SecondInitializer());
  8. springApplication.run(args);
  9. }
  10. }

第三种:在application.properties配置context.initializer.classes

1、新建ThirdInitializer.java

  1. @Order(3)
  2. public class ThirdInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  3. @Override
  4. public void initialize(ConfigurableApplicationContext applicationContext) {
  5. ConfigurableEnvironment environment = applicationContext.getEnvironment();
  6. Map<String, Object> map = new HashMap<>();
  7. map.put("key3", "value3");
  8. MapPropertySource mps = new MapPropertySource("thirdInitializer", map);
  9. environment.getPropertySources().addLast(mps);
  10. System.out.println("#############ThirdInitializer.initialize 运行");
  11. }
  12. }

2、在application.properties中配置

context.initializer.classes=com.example.springbootdemo.ThirdInitializer

3、启动工程,控制台有以下输出

#############ThirdInitializer.initialize 运行
#############FirstInitializer.initialize 运行
#############SecondInitializer.initialize 运行
#############FirstOrderedInitializer.initialize 运行

ThirdInitializer的注解是@Order(3),但是ThirdInitializer比FirstInitializer、SecondInitializer先运行。是不是使用context.initializer.classes配置的初始化器就会先运行呢?后面会回答这问题。

源码讲解

spring boot 版本是2.2.4.RELEASE。

先把启动类SpringBootDemoApplication.java的代码还原为 

SpringApplication.run(SpringBootDemoApplication.class, args);

使用最常规的启动方式来分析spring boot 的源码。

1、进入run方法内,直到看见如下代码:

  1. // 源码位置org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])
  2. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  3. return new SpringApplication(primarySources).run(args);
  4. }

可粗略的得出一个结论,spring boot 使用一句代码 SpringApplication.run(SpringBootDemoApplication.class, args); 启动工程,本质上是创建SpringApplication实例,再运行实例的run方法。run方法执行完,工程就启动完成了。

1.1、继续debug,进入SpringApplication的构造函数中

  1. // 源码位置 org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
  2. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  3.     this.resourceLoader = resourceLoader;
  4.     Assert.notNull(primarySources, "PrimarySources must not be null");
  5.     this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  6.     this.webApplicationType = WebApplicationType.deduceFromClasspath();
  7. // 这行代码就是设置初始化器
  8.     setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  9.     setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  10.     this.mainApplicationClass = deduceMainApplicationClass();
  11. }

1.1.1、setInitializers方法源码如下:

  1. // 源码位置 org.springframework.boot.SpringApplication#setInitializers
  2. public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
  3. /**
  4. * 系统初始化器可以有多个,形成一个系统初始化器列表。
  5. * 在创建SpringApplication对象时,将系统初始化器列表赋值给SpringApplication的initializers属性。
  6. */
  7.     this.initializers = new ArrayList<>(initializers);
  8. }

1.1.2、getSpringFactoriesInstances(ApplicationListener.class)是获取系统初始化器的函数

进入方法体中debug

  1. // 源码位置 org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
  2. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  3. ClassLoader classLoader = getClassLoader();
  4. // Use names and ensure unique to protect against duplicates
  5. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  6. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  7. AnnotationAwareOrderComparator.sort(instances);
  8. return instances;
  9. }

1.1.2.1、ClassLoader classLoader = getClassLoader();

getClassLoader()返回结果是AppClassLoader实例。
Java自带了3个类加载器:BootstrapClassLoader、ExtClassLoader、AppClassLoader。AppClassLoader会加载classpath路径下jar包和目录的class文件。我们自己编写的代码以及代码依赖的第三方jar包通常都是由它来加载的。
可运行System.getProperty("java.class.path"),查看当前工程的classpath是什么。

1.1.2.2、Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));

type是ApplicationContextInitializer接口,这句代码是获取type接口实现类的类全名集合。进入到SpringFactoriesLoader.loadFactoryNames方法内部。

  1. // 源码位置 org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
  2. public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  3. String factoryTypeName = factoryType.getName();
  4. /**
  5. * 重点代码是 loadSpringFactories(classLoader)。
  6. * 先讲结论,loadSpringFactories(classLoader)返回一个LinkedMultiValueMap对象,此对象一个key对应多个value。
  7. * key是接口全类名,value是接口的实现类全类名,value可以有多个。
  8. */
  9. return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
  10. }

debug到loadSpringFactories(classLoader)内部

  1. // 源码位置 org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories
  2. private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  3. MultiValueMap<String, String> result = cache.get(classLoader);
  4. if (result != null) {
  5. return result;
  6. }
  7. try {
  8. /**
  9. * FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  10. * 通过AppClassLoader加载Classpath下的META-INF/spring.factories
  11. * 当前工程和依赖的第三方jar包中的META-INF/spring.factories都会被加载进来
  12. */
  13. Enumeration<URL> urls = (classLoader != null ?
  14. classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
  15. ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
  16. result = new LinkedMultiValueMap<>();
  17. while (urls.hasMoreElements()) {
  18. URL url = urls.nextElement();
  19. // resource是包含了spring.factories文件路径的资源对象
  20. UrlResource resource = new UrlResource(url);
  21. // 使用spring.factories中配置的键值对创建Properties对象
  22. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  23. // 循环properties的键值对
  24. for (Map.Entry<?, ?> entry : properties.entrySet()) {
  25. String factoryTypeName = ((String) entry.getKey()).trim();
  26. for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
  27. /**
  28. * factoryTypeName是spring.factories中配置的key,比如:ApplicationContextInitializer接口全类名
  29. * factoryImplementationName是key对应的value,比如:ApplicationContextInitializer实现类FirstInitializer的全类名
  30. */
  31. result.add(factoryTypeName, factoryImplementationName.trim());
  32. }
  33. }
  34. }
  35. cache.put(classLoader, result);
  36. /**
  37. * result是一个LinkedMultiValueMap。key是接口全名,value是接口的实现类全类名,value可以是多个。
  38. * 需要注意的是:
  39. * 1、AppClassLoader会获取Classpath下所有jar包的spring.factories文件
  40. * 2、并将spring.factories中所有的配置添加到result中
  41. * 基于以上两点,就不难理解为什么要用缓存了
  42. * cache.put(classLoader, result); 、 MultiValueMap<String, String> result = cache.get(classLoader);
  43. * AppClassLoader把classpath下所有的spring.factories读取到缓存中。下次要用spring.factories配置时,从缓存中拿就好了
  44. */
  45. return result;
  46. }
  47. catch (IOException ex) {
  48. throw new IllegalArgumentException("Unable to load factories from location [" +
  49. FACTORIES_RESOURCE_LOCATION + "]", ex);
  50. }
  51. }

在此总结下 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); 这行代码的作用。大致分为以下2个小步骤:

1、使用AppClassLoader获取Classpath下的spring.factories文件的路径

2、读取spring.factories并创建properties对象

3、将type接口(本文中type是ApplicationContextInitializer)实现类的类全名返回。第三方jar包spring.factories中配置的ApplicationContextInitializer实现类的全类名也会被读取并返回,所以结果是Set<String>类型。

1.1.2.3、List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

获得了系统初始化的全类名集合,就能创建系统初始化器实例集合了,源码如下:

  1. // 源码位置 org.springframework.boot.SpringApplication#createSpringFactoriesInstances
  2. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
  3. ClassLoader classLoader, Object[] args, Set<String> names) {
  4. List<T> instances = new ArrayList<>(names.size());
  5. for (String name : names) {
  6. try {
  7. // AppClassLoader使用类全名把类加载到jvm内存中
  8. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  9. Assert.isAssignable(type, instanceClass);
  10. // 获取系统初始化器的构造器
  11. Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
  12. // 通过构造器创建实例
  13. T instance = (T) BeanUtils.instantiateClass(constructor, args);
  14. // 添加到集合中
  15. instances.add(instance);
  16. }
  17. catch (Throwable ex) {
  18. throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
  19. }
  20. }
  21. // 返回系统初始化器实例集合
  22. return instances;
  23. }

1.1.2.4、AnnotationAwareOrderComparator.sort(instances); 这是对系统初始化器实例集合进行排序。

debug到如下代码内

  1. // 源码位置 org.springframework.core.OrderComparator#doCompare()
  2. private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
  3. boolean p1 = (o1 instanceof PriorityOrdered);
  4. boolean p2 = (o2 instanceof PriorityOrdered);
  5. if (p1 && !p2) {
  6. return -1;
  7. }
  8. else if (p2 && !p1) {
  9. return 1;
  10. }
  11. /**
  12. * getOrder方法很复杂,本文只关注getOrder方法的两个作用。
  13. * 1、获取@Order注解值
  14. * 2、获取Ordered接口getOrder方法返回值
  15. */
  16. int i1 = getOrder(o1, sourceProvider);
  17. int i2 = getOrder(o2, sourceProvider);
  18. // 排序规则是升序
  19. return Integer.compare(i1, i2);
  20. }

在以下代码中打上断点,运行程序debug
com.example.springbootdemo.FirstOrderedInitializer#getOrder()
    // 调用Ordered实现类的getOrder()方法,获取排序值 
    return 2;     
org.springframework.core.annotation.OrderUtils#findOrder()
    // getOrder方法获取@Order注解的值 
    MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
    if (orderAnnotation.isPresent()) {
        return orderAnnotation.getInt(MergedAnnotation.VALUE);
    }

至此,系统初始化器的初始化代码就讲完了。重点是getSpringFactoriesInstances方法,下面对此方法做总结:

  1. // 源码位置 org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>, java.lang.Class<?>[], java.lang.Object...)
  2. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  3. // getClassLoader()返回AppClassLoader
  4. ClassLoader classLoader = getClassLoader();
  5. // 获取系统初始化器全类名集合
  6. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  7. // 创建系统初始化器集合
  8. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  9. // 对系统初始化器排序
  10. AnnotationAwareOrderComparator.sort(instances);
  11. // 返回排序后的系统初始化器集合
  12. return instances;
  13. }

FirstInitializer添加到SpringApplication.initializers的原理已经讲清楚了。

SecondInitializer添加给SpringApplication.initializers的方式就很简单了,springApplication.addInitializers(new SecondInitializer());  的源码如下:

  1. // 源码位置 org.springframework.boot.SpringApplication#addInitializers
  2. public void addInitializers(ApplicationContextInitializer<?>... initializers) {
  3. this.initializers.addAll(Arrays.asList(initializers));
  4. }

目前遗留下两个问题:

1、SecondInitializer:addAll是将SecondInitializer添加到this.initializers的末尾,排序位置不对。

2、ThirdInitializer通过application.properties配置,还没被添加到this.initializers中。

带着这两个疑问,我们来探究  new SpringApplication(primarySources).run(args);  的run方法,即SpringApplication的运行阶段。

使用 SpringApplication.run(SpringBootDemoApplication.class, args); 启动程序。在源码中是执行 new SpringApplication(primarySources).run(args); 这句代码跟前面介绍第二种配置系统初始化器的代码很相似,为了配置SecondInitializer,需要把启动类的代码改成

  1. @SpringBootApplication
  2. public class SpringBootDemoApplication {
  3. public static void main(String[] args) {
  4. //SpringApplication.run(SpringBootDemoApplication.class, args);
  5. // 第2中添加系统初始化器的方式
  6. SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
  7. springApplication.addInitializers(new SecondInitializer());
  8. springApplication.run(args); // 这句代码打上断点调试
  9. }
  10. }

在 springApplication.run(args); 这句代码打上断点,启动工程、调试。

debug到run方法内

  1. // 源码位置 org.springframework.boot.SpringApplication.run(java.lang.String...)
  2. public ConfigurableApplicationContext run(String... args) {
  3. /**
  4. * run方法很复杂,本文作为spring boot源码系列的第一篇博客,仅关注系统初始化器相关代码。其他代码忽略
  5. * prepareContext方法内会运行系统初始化器
  6. */
  7. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  8. // ApplicationContextInitializer接口文档第三点
  9. refreshContext(context);
  10. }

debug到prepareContext方法中

  1. // 源码位置 org.springframework.boot.SpringApplication.prepareContext
  2. private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
  3. SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  4. // 应用初始化器
  5. applyInitializers(context);
  6. }

applyInitializers方法源码:

  1. // 源码位置 org.springframework.boot.SpringApplication#applyInitializers
  2. protected void applyInitializers(ConfigurableApplicationContext context) {
  3. /**
  4. * getInitializers()获取系统初始化器,并且对系统系统初始化器再次排序,解决了SecondInitializer的排序问题
  5. * 循环系统初始化器,并执行系统初始化器的initialize方法
  6. */
  7. for (ApplicationContextInitializer initializer : getInitializers()) {
  8. Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
  9. ApplicationContextInitializer.class);
  10. Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
  11. initializer.initialize(context);
  12. }
  13. }

1、getInitializers()获取系统初始化器,并且对系统系统初始化器再次排序

  1. // 源码位置 org.springframework.boot.SpringApplication#asUnmodifiableOrderedSet
  2. private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {
  3. List<E> list = new ArrayList<>(elements);
  4. // 再次对系统初始化器集合排序
  5. list.sort(AnnotationAwareOrderComparator.INSTANCE);
  6. return new LinkedHashSet<>(list);
  7. }

2、getInitializers()获得系统初始化器集合,排在第一位的系统初始化器是DelegatingApplicationContextInitializer(委派系统初始化器,Order值是0),它会将初始化操作委派给环境属性context.initializer.classes指定的初始化器。

DelegatingApplicationContextInitializer.initialize方法源码如下

  1. // 源码位置org.springframework.boot.context.config.DelegatingApplicationContextInitializer#initialize
  2. public void initialize(ConfigurableApplicationContext context) {
  3. // 获取环境变量
  4. ConfigurableEnvironment environment = context.getEnvironment();
  5. // 获取context.initializer.classes配置的初始化器集合
  6. List<Class<?>> initializerClasses = getInitializerClasses(environment);
  7. if (!initializerClasses.isEmpty()) {
  8. // 执行初始化器的initialize方法
  9. applyInitializerClasses(context, initializerClasses);
  10. }
  11. }

2.1  getInitializerClasses(environment); 源码分析

  1. // 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#getInitializerClasses
  2. private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
  3. // PROPERTY_NAME = "context.initializer.classes"
  4. String classNames = env.getProperty(PROPERTY_NAME);
  5. List<Class<?>> classes = new ArrayList<>();
  6. if (StringUtils.hasLength(classNames)) {
  7. // 通过","分隔context.initializer.classes的值
  8. for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
  9. // getInitializerClass(className)使用AppClassLoader加载类
  10. classes.add(getInitializerClass(className));
  11. }
  12. }
  13. return classes;
  14. }

2.2、applyInitializerClasses(context, initializerClasses);源码分析

  1. // 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializerClasses
  2. private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
  3. Class<?> contextClass = context.getClass();
  4. List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();
  5. // initializerClasses是context.initializer.classes指定的类集合
  6. for (Class<?> initializerClass : initializerClasses) {
  7. // 实例化系统初始化器
  8. initializers.add(instantiateInitializer(contextClass, initializerClass));
  9. }
  10. // 应用系统初始化器
  11. applyInitializers(context, initializers);
  12. }

2.2.1 applyInitializers(context, initializers); 源码分析

  1. // 源码位置 org.springframework.boot.context.config.DelegatingApplicationContextInitializer#applyInitializers
  2. private void applyInitializers(ConfigurableApplicationContext context,
  3. List<ApplicationContextInitializer<?>> initializers) {
  4. // 先排序,这里是对context.initializer.classes配置的系统初始化器进行排序
  5. initializers.sort(new AnnotationAwareOrderComparator());
  6. for (ApplicationContextInitializer initializer : initializers) {
  7. // 执行初始化器的initialize方法,会进入 ThirdInitializer#initialize 方法中
  8. initializer.initialize(context);
  9. }
  10. }

ThirdInitializer就被调用了。现在对DelegatingApplicationContextInitializer(委派系统初始化器)做个总结:

1、DelegatingApplicationContextInitializer的排序值是0,比FirstInitializer、SecondInitializer的排序值小,最先被调用。

2、DelegatingApplicationContextInitializer实例化context.initializer.classes配置的系统初始化器,并运行这些系统初始化器的initialize方法。所以context.initializer.classes配置的系统初始化器会先运行。

3、DelegatingApplicationContextInitializer的排序值是0,若把FirstInitializer的排序值设置为小于0,则FirstInitializer会先运行。

讲完了ThirdInitializer的实例化、运行过程。在回到 org.springframework.boot.SpringApplication#applyInitializers方法中,继续讲解FirstInitializer、FirstOrderedInitializer、SecondInitializer的运行过程

  1. // 源码位置 org.springframework.boot.SpringApplication#applyInitializers
  2. protected void applyInitializers(ConfigurableApplicationContext context) {
  3. /**
  4. * 循环处理getInitializers()返回的系统初始化器,
  5. * 排在第一位的是DelegatingApplicationContextInitializer,前面已经讲了此初始化器的运行过程
  6. * 后面几次循环获得的initializer包含FirstInitializer、FirstOrderedInitializer、SecondInitializer
  7. * initializer.initialize(context);就直接运行我们自定义的系统初始化器了
  8. */
  9. for (ApplicationContextInitializer initializer : getInitializers()) {
  10. Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
  11. ApplicationContextInitializer.class);
  12. Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
  13. initializer.initialize(context);
  14. }
  15. }

好了,spring boot 2系统初始化器的使用与源码都讲完了,后面我会继续更新 spring boot 源码系列 ,欢迎大家来一起交流。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/479543
推荐阅读
相关标签
  

闽ICP备14008679号