SpringBoot——初始化器解析

时间:2023-01-14 18:55:33

初始化器

Spring 是一个扩展性很强的容器框架,为开发者提供了丰富的扩展入口,其中一个扩展点便是 ApplicationContextInitializer (应用上下文初始化器 )。

 

ApplicationContextInitializer 是 Spring 在执行 ConfigurableApplicationContext.refresh() 方法对应用上下文进行刷新之前调用的一个回调接口,用来完成对 Spring 应用上下文个性化的初始化工作,该接口定义在 org.springframework.context 包中,其内部仅包含一个 initialize() 方法,其定义代码如下。 

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);

}

自定义初始化器

在 Springboot 中使用自定义初始化器大致可以分为以下两个步骤:

  • 自定义初始化器,一般是实现 ApplicationContextInitializer 接口。
  • 注册初始化器。

第一步:自定义初始化器,此处为了测试初始化器的执行顺序定义了如下3个初始化器

@Order(1)
public class Initializer1 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String,Object> map = new HashMap<>();
        map.put("key1","value1");
        MapPropertySource mapPropertySource = new MapPropertySource("Initializer1", map);
        environment.getPropertySources().addLast(mapPropertySource);
        System.out.println("run Initializer1");
    }
}
@Order(2)
public class Initializer2 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String,Object> map = new HashMap<>();
        map.put("key2","value2");
        MapPropertySource mapPropertySource = new MapPropertySource("Initializer2", map);
        environment.getPropertySources().addLast(mapPropertySource);
        System.out.println("run Initializer2");
    }
}
@Order(3)
public class Initializer3 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        Map<String,Object> map = new HashMap<>();
        map.put("key3","value3");
        MapPropertySource mapPropertySource = new MapPropertySource("Initializer3", map);
        environment.getPropertySources().addLast(mapPropertySource);
        System.out.println("run Initializer3");
    }
}

第二步:注册初始化器,有以下三种方式

  • 方式一:在启动类中,使用 SpringApplication.addInitializers() 方法注册。
@SpringBootApplication
@MapperScan("com.yibo.source.code.mapper")//扫描Mapper接口
public class Application {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(Application.class);
        springApplication.addInitializers(new Initializer2());
        springApplication.run();
    }
}
  • 方式二:在 Springboot 核心配置文件 application.properties 中增加 context.initializer.classes = [ 初始化器全类名 ] 进行注册。
context.initializer.classes=com.yibo.source.code.initializer.Initializer3
  • 方式三:通过在CLASSPATH/META-INF/spring.factories中添加 org.springframework.context.ApplicationContextInitializer 配置项进行注册。
org.springframework.context.ApplicationContextInitializer=com.yibo.source.code.initializer.Initializer1

注意:虽然可以使用 @Order 注解来控制多个初始化器的执行顺序(数值越小越先执行),但是,通过不同方式注册的初始化器的执行顺序也有所不同,若多个初始化器注册的方式不同会导致 @Order 注解顺序无效,从以上程序执行后的打印结果来看,三种方式注册的初始化器的执行顺序依次是:方式二 --> 方式一 --> 方式三。 

Springboot定义的初始化器

Springboot定义的 ApplicationContextInitializer 接口的实现类有下面几个,如图所示。
SpringBoot——初始化器解析

DelegatingApplicationContextInitializer

DelegatingApplicationContextInitializer 初始化器负责读取核心配置文件 context.initializer.classes 配置项指定的初始化器,并调用它们的 initialize() 方法来完成对应用上下文的初始化工作。  

public class DelegatingApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    private static final String PROPERTY_NAME = "context.initializer.classes";
    private int order = 0;

    public DelegatingApplicationContextInitializer() {
    }

	/**
	 * 对应用上下文进行初始化
	 */
    public void initialize(ConfigurableApplicationContext context) {
		// 获取核心配置文件中指定的初始化器类
        ConfigurableEnvironment environment = context.getEnvironment();
        List<Class<?>> initializerClasses = this.getInitializerClasses(environment);
        if (!initializerClasses.isEmpty()) {
			// 利用获取到的初始化器类对应用上下文进行初始化
            this.applyInitializerClasses(context, initializerClasses);
        }

    }

	/**
	 * 读取核心配置文件中 context.initializer.classes 指定的初始化器类
	 */
    private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
        String classNames = env.getProperty("context.initializer.classes");
        List<Class<?>> classes = new ArrayList();
        if (StringUtils.hasLength(classNames)) {
            String[] var4 = StringUtils.tokenizeToStringArray(classNames, ",");
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String className = var4[var6];
                classes.add(this.getInitializerClass(className));
            }
        }

        return classes;
    }

	/**
	 * 使用指定的初始化器类对应用上下文进行初始化
	 */
    private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
        Class<?> contextClass = context.getClass();
        List<ApplicationContextInitializer<?>> initializers = new ArrayList();
        Iterator var5 = initializerClasses.iterator();

        while(var5.hasNext()) {
            Class<?> initializerClass = (Class)var5.next();
            initializers.add(this.instantiateInitializer(contextClass, initializerClass));
        }

        this.applyInitializers(context, initializers);
    }


	/**
	 * 使用指定的初始化器对应用上下文进行初始化
	 */
    private void applyInitializers(ConfigurableApplicationContext context, List<ApplicationContextInitializer<?>> initializers) {
        // 对初始化器进行 Order 排序
		initializers.sort(new AnnotationAwareOrderComparator());
        Iterator var3 = initializers.iterator();

        while(var3.hasNext()) {
            ApplicationContextInitializer initializer = (ApplicationContextInitializer)var3.next();
            initializer.initialize(context);
        }

    }
	......
}

ContextIdApplicationContextInitializer

ContextIdApplicationContextInitializer 初始化器的作用是给应用上下文设置一个ID,这个ID通过environment中的"spring.application.name"获取,如果不存在则直接返回默认"application"

public class ContextIdApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    private int order = 2147483637;

    public ContextIdApplicationContextInitializer() {
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public int getOrder() {
        return this.order;
    }

    public void initialize(ConfigurableApplicationContext applicationContext) {
        ContextIdApplicationContextInitializer.ContextId contextId = this.getContextId(applicationContext);
        applicationContext.setId(contextId.getId());
        applicationContext.getBeanFactory().registerSingleton(ContextIdApplicationContextInitializer.ContextId.class.getName(), contextId);
    }

    private String getApplicationId(ConfigurableEnvironment environment) {
        String name = environment.getProperty("spring.application.name");
        return StringUtils.hasText(name) ? name : "application";
    }
}

ConfigurationWarningsApplicationContextInitializer

ConfigurationWarningsApplicationContextInitializer 初始化器用来对常见的由于配置错误而引起的警告进行打印报告。

public class ConfigurationWarningsApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    private static final Log logger = LogFactory.getLog(ConfigurationWarningsApplicationContextInitializer.class);

    public void initialize(ConfigurableApplicationContext context) {
		// 添加一个 ConfigurationWarningsPostProcessor 用来打印警告信息
        context.addBeanFactoryPostProcessor(new ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(this.getChecks()));
    }
}

其中的 ConfigurationWarningsPostProcessor 是一个静态内部类,用来打印注册 BeanDefinition 过程中产生的配置错误警告信息。

protected static final class ConfigurationWarningsPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
	private ConfigurationWarningsApplicationContextInitializer.Check[] checks;

	public ConfigurationWarningsPostProcessor(ConfigurationWarningsApplicationContextInitializer.Check[] checks) {
		this.checks = checks;
	}

	public int getOrder() {
		return 2147483646;
	}

	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	}

	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		ConfigurationWarningsApplicationContextInitializer.Check[] var2 = this.checks;
		int var3 = var2.length;

		for(int var4 = 0; var4 < var3; ++var4) {
			ConfigurationWarningsApplicationContextInitializer.Check check = var2[var4];
			String message = check.getWarning(registry);
			if (StringUtils.hasLength(message)) {
				this.warn(message);
			}
		}

	}

	private void warn(String message) {
		if (ConfigurationWarningsApplicationContextInitializer.logger.isWarnEnabled()) {
			ConfigurationWarningsApplicationContextInitializer.logger.warn(String.format("%n%n** WARNING ** : %s%n%n", message));
		}

	}
}

ServerPortInfoApplicationContextInitializer

ServerPortInfoApplicationContextInitializer 初始化器通过监听 EmbeddedServletContainerInitializedEvent 事件,来对内部服务器实际要监听的端口号进行属性设置。 

public class ServerPortInfoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, ApplicationListener<WebServerInitializedEvent> {
    public ServerPortInfoApplicationContextInitializer() {
    }

    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addApplicationListener(this);
    }

    public void onApplicationEvent(WebServerInitializedEvent event) {
        String propertyName = "local." + this.getName(event.getApplicationContext()) + ".port";
        this.setPortProperty((ApplicationContext)event.getApplicationContext(), propertyName, event.getWebServer().getPort());
    }

    private String getName(WebServerApplicationContext context) {
        String name = context.getServerNamespace();
        return StringUtils.hasText(name) ? name : "server";
    }

    private void setPortProperty(ApplicationContext context, String propertyName, int port) {
        if (context instanceof ConfigurableApplicationContext) {
            this.setPortProperty(((ConfigurableApplicationContext)context).getEnvironment(), propertyName, port);
        }

        if (context.getParent() != null) {
            this.setPortProperty(context.getParent(), propertyName, port);
        }

    }

    private void setPortProperty(ConfigurableEnvironment environment, String propertyName, int port) {
        MutablePropertySources sources = environment.getPropertySources();
        PropertySource<?> source = sources.get("server.ports");
        if (source == null) {
            source = new MapPropertySource("server.ports", new HashMap());
            sources.addFirst((PropertySource)source);
        }

        ((Map)((PropertySource)source).getSource()).put(propertyName, port);
    }
}

SharedMetadataReaderFactoryContextInitializer

SharedMetadataReaderFactoryContextInitializer 初始化器用来创建一个可以在 ConfigurationClassPostProcessor 和Spring Boot 之间共享的CachingMetadataReaderFactory。 

class SharedMetadataReaderFactoryContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    public static final String BEAN_NAME = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory";

    SharedMetadataReaderFactoryContextInitializer() {
    }

    public void initialize(ConfigurableApplicationContext applicationContext) {
        applicationContext.addBeanFactoryPostProcessor(new SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor());
    }
}

看下SpringBoot是如何加载初始化器的

入口类

@SpringBootApplication
@MapperScan("com.yibo.source.code.mapper")//扫描Mapper接口
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

@SpringBootApplication我们上一篇文章https://blog.51cto.com/u_14014612/6007650 中大概的讲过了,有兴趣的可以看看我第一篇关于SpringBoot的文章,本篇文章主要关注SpringApplication.run(Application.class, args);,我们跟进去看看

// 调用静态类,参数对应的就是HelloWorldMainApplication.class以及main方法中的args
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class[]{primarySource}, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return (new SpringApplication(primarySources)).run(args);
}

它实际上会构造一个SpringApplication的实例,并把我们的启动类Application.class作为参数传进去,然后运行它的run方法 SpringApplication构造器

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.sources = new LinkedHashSet();
	this.bannerMode = Mode.CONSOLE;
	this.logStartupInfo = true;
	this.addCommandLineProperties = true;
	this.addConversionService = true;
	this.headless = true;
	this.registerShutdownHook = true;
	this.additionalProfiles = new HashSet();
	this.isCustomEnvironment = false;
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	//把Application.class设置为属性存储起来
	this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
	//设置应用类型是Standard还是Web
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	//设置初始化器(Initializer),最后会调用这些初始化器
	this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
	//设置监听器(Listener)
	this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = this.deduceMainApplicationClass();
}

设置应用类型

public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;

    private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
    private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
    private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
    private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
    private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
    private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

    private WebApplicationType() {
    }

    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }

            return SERVLET;
        }
    }
}

这里主要是通过类加载器判断REACTIVE相关的Class是否存在,如果不存在,则web环境即为SERVLET类型。这里设置好web环境类型,在后面会根据类型初始化对应环境。大家还记得我们第一篇文章中引入的依赖吗?

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter-web 的pom又会引入Tomcat和spring-webmvc,如下

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-json</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.1.10.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.18.Final</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.11.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.11.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

SpringBoot——初始化器解析

很明显spring-webmvc中存在DispatcherServlet这个类,也就是我们以前SpringMvc的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么我们的应用类型自然就是WebApplicationType.SERVLET

设置初始化器(Initializer)

this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));

我们先来看看this.getSpringFactoriesInstances(ApplicationContextInitializer.class)

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
	return this.getSpringFactoriesInstances(type, new Class[0]);
}

// 这里的入参type就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = this.getClassLoader();
	// 使用Set保存names来避免重复元素
	Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	// 根据names来进行实例化
	List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	// 对实例进行排序
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

这里面首先会根据入参type读取所有的names(是一个String集合),然后根据这个集合来完成对应的实例化操作:

public final class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	// 入参就是ApplicationContextInitializer.class
    public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }

    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
        MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
				//从类路径的META-INF/spring.factories中加载所有默认的自动配置类
                Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
						//获取ApplicationContextInitializer.class的所有值
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;

                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }

                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }
}

这个方法会尝试从类路径的META-INF/spring.factories处读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value。以spring-boot-autoconfigure这个包为例,它的META-INF/spring.factories部分定义如下所示: SpringBoot——初始化器解析

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

这两个类名会被读取出来,然后放入到Set<String>集合中,准备开始下面的实例化操作:

// parameterTypes: 上一步得到的names集合
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
	List<T> instances = new ArrayList(names.size());
	Iterator var7 = names.iterator();

	while(var7.hasNext()) {
		String name = (String)var7.next();

		try {
			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
			//确认被加载类是ApplicationContextInitializer的子类
			Assert.isAssignable(type, instanceClass);
			Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
			//反射实例化对象
			T instance = BeanUtils.instantiateClass(constructor, args);
			//加入List集合中
			instances.add(instance);
		} catch (Throwable var12) {
			throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
		}
	}

	return instances;
}

确认被加载的类确实是org.springframework.context.ApplicationContextInitializer的子类,然后就是得到构造器进行初始化,最后放入到实例列表中。

 

因此,所谓的初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,这个接口是这样定义的:

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);

}

在Spring上下文被刷新之前进行初始化的操作。即在SpringApplication.prepareContext方法中调用applyInitializers方法进行初始化操作,典型地比如在Web应用中,注册Property Sources或者是激活Profiles。Property Sources比较好理解,就是配置文件。Profiles是Spring为了在不同环境下(如DEV,TEST,PRODUCTION等),加载不同的配置项而抽象出来的一个实体。

public class SpringApplication {
	public ConfigurableApplicationContext run(String... args) {
		......
		this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		......
	}
	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		......
		this.applyInitializers(context);
		......

	}
}

SpringFactoriesLoader介绍

  • 1、框架内部使用的通用工厂加载机制
  • 2、从classpath下多个jar包特定的位置读取文件并初始化类
  • 3、文件内容必须是kv形式,即properties类型
  • 4、key是全限定名,value是实现,多个实现用逗号分隔

SpringFactoriesLoader的作用

SpringBoot框架中从类路径jar包中读取特定文件实现扩展类的载入 SpringBoot——初始化器解析

SpringBoot——初始化器解析

系统初始化器调用流程

SpringBoot——初始化器解析

文章开始的三种自定义初始化器实现原理

  • 定义在spring.factories文件中被SpringFactoriesLoader发现注册
  • SpringApplication初始化完毕后手动添加
  • 定义成环境变量被DelegatingApplicationContextInitializer发现注册

推荐使用在spring.factories文件中定义系统初始化器被SpringFactoriesLoader发现注册的方式

在spring.factories文件中定义系统初始化器,被SpringFactoriesLoader载入,成为SpringBoot框架的SpringApplicationInitializer属性,在运行的时候会遍历这个属性依次调用initialize方法完成向容器内注册属性。 SpringBoot——初始化器解析

参考: https://blog.csdn.net/pengjunlee/article/details/79394735

https://www.cnblogs.com/java-chen-hao/p/11829344.html