首页 > 其他分享 >SpringBoot——初始化器解析

SpringBoot——初始化器解析

时间:2023-01-14 18:31:50浏览次数:52  
标签:初始化 SpringBoot ApplicationContextInitializer context new 解析 public String

初始化器

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 接口的实现类有下面几个,如图所示。

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>

很明显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部分定义如下所示:

# 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包中读取特定文件实现扩展类的载入

系统初始化器调用流程

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

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

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

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

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

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

标签:初始化,SpringBoot,ApplicationContextInitializer,context,new,解析,public,String
From: https://blog.51cto.com/u_14014612/6007651

相关文章

  • SpringBoot——监听器解析
    监听器模式监听器模式有要素事件监听器广播器触发机制系统监听器监听器ApplicationListener@FunctionalInterfacepublicinterfaceApplicationListener<Eext......
  • ArrayList源码解析
    ArrayList核心成员变量privatestaticfinalintDEFAULT_CAPACITY=10;privatestaticfinalObject[]EMPTY_ELEMENTDATA={};privatestaticfinalObject[]DEFAU......
  • XML及JSON扩展方法,方便快速解析
    #regionXML扩展方法///<summary>///从xml节点中获取指定属性的数据,如果不存在该属性则返回默认值///</summary>///<typeparamname="T">xml数据的数据类型</type......
  • oracle rowid字段解析
    文档课题:oraclerowid字段解析.1、相关概念rowid是一行数据的唯一标识,是数据的详细地址,通过rowid可快速定位某行数据的具体位置.其可分为物理rowid和逻辑rowid.普通堆表的r......
  • 一个使用Win32api的简单乐谱解析器
    音调数据enumscale{Rest=0,A0=21,A0s=22,B0=23, C1=24,C1s=25,D1=26,D1s=27,E1=28,F1=29,F1s=30,G1=......
  • 230113_50_SpringBoot入门
    EnableAutoConfiguration详解​ SpringBoot可以实现自动配置;@EnableAutoConfiguration注解用于告知springboot开启自动配置功能,这样自动配置才能生效。@AutoConfigura......
  • CentOS 7.6 kubernetes v.1.17  系统初始化脚本
    本文基于CentOS7.6kubernetesv.1.17 系统初始化,供参考#!/bin/bash#data:2019-12-10#centos7.6#角色划分#Master|Kube-apiserver,kube-controller-manager,kube-sc......
  • python实战-解析swagger-api接口信息
    *coding:UTF-8*"""@project->file:city-test->swagger_api_parse_backup@Author:qinmin.vendor@Date:2023/1/1217:55@Desc......
  • SpringBoot 项目中配置多个 Jackson 的 ObjectMapper ,以及配置遇到的坑
    目录问题说明原因排查分析结论总结Jackson自动装配分析问题说明我们都知道,SpringBoot项目中,如果引入了Jackson的包,哪怕不配置,SpringBoot也会帮我们配置(JacksonAutoC......
  • underscore源码解析之二: underscore是如何实现防抖的?
    前言Underscore是一个JavaScript库,提供了各种函数式编程辅助工具。它提供的功能之一是防抖,这是一种限制函数执行频率的技术。在本文中,我们将探讨Underscore如何实现......