SpringBoot配置文件加载过程

前置知识

配置属性抽象和各种实现类

PropertySource<T>

下面是 抽象类属性源 和 它的两个内部实现类 介绍

// 抽象父类
public abstract class PropertySource<T> {
    /**  属性源名称  **/
    protected final String name;
    /**  属性源数据  **/
	protected final T source;
    
    /** 从source里面获取Property,要public T getSource(){}区别开   
    getSource是获取整个source字段,getProperty是从source里面查询指定Property  **/
    @Nullable
	public abstract Object getProperty(String name);
    
    
    // PropertySource的内部实现类  主要作用是占据一个位置,后面再用实际的属性源替换
    /**  在应用程序上下文创建时无法急切地初始化实际属性源的情况下,可以将属性源用作占位符。
    例如,ServletContext-based属性源必须等到ServletContext对象对其封闭的Application ationContext可用。
    在这种情况下,应该使用存根来保存属性源的预期默认位置/顺序,然后在上下文刷新期间替换。  **/
    public static class StubPropertySource extends PropertySource<Object> {

		public StubPropertySource(String name) {
			super(name, new Object());
		}

		/**
		 * 重写了父类的getProperty方法,直接返回 Null 值 ,
		 */
		@Override
		@Nullable
		public String getProperty(String name) {
			return null;
		}
	}
    
    
    
   	/**用于集合比较目的的PropertySource实现。 主要的方法实现都直接抛出异常 */
	static class ComparisonPropertySource extends StubPropertySource {

		private static final String USAGE_ERROR =
				"ComparisonPropertySource instances are for use with collection comparison only";

		public ComparisonPropertySource(String name) {
			super(name);
		}

		@Override
		public Object getSource() {
			throw new UnsupportedOperationException(USAGE_ERROR);
		}

		@Override
		public boolean containsProperty(String name) {
			throw new UnsupportedOperationException(USAGE_ERROR);
		}

		@Override
		@Nullable
		public String getProperty(String name) {
			throw new UnsupportedOperationException(USAGE_ERROR);
		}
	} 
}

EnumerablePropertySource<T>

可枚举的抽象子类

/**  子类通过通过实现 getPropertyNames() 方法获取到属性源的所有 Property名称,
然后通过遍历可以枚举所有 Property, 大多数框架提供的属性源实现都是可枚举的    */
public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
    
	/**  返回源对象包含的所有属性的名称(从不为空) */
	public abstract String[] getPropertyNames();
    
	@Override
	public boolean containsProperty(String name) {
        /** 通过 getPropertyNames() 返回 查询是否包含指定的 Property */
		return ObjectUtils.containsElement(getPropertyNames(), name);
	}

}

CompositePropertySource

复合属性源

/**  迭代一组属性源实例的复合属性源实现。在多个属性源共享相同名称的情况下是必要的,  */
public class CompositePropertySource extends EnumerablePropertySource<Object> {

    private final Set<PropertySource<?>> propertySources = new LinkedHashSet<>();
    
    /**  这个实现类本质就是多个 PropertySource 聚合到一起,共用一个 name 属性,链表内的属性源的 name 属性都会被忽略。
    然后根据这个特点,重新实现了父类的主要方法,如: getPropertyNames ,containsProperty 等 
    最后 再有添加了一些操作propertySources链表的方法,如: addPropertySource,getPropertySources等*/
    
}

配置加载过程:

// 这一步会生成一个完整的 ConfigurableEnvironment 对象
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

一、生成Environment对象

生成一个Environment实现类对象,根据不同的类型初始化的实现类不同,内部逻辑也稍有不同

// 根据不同的环境生成不同类型的 ConfigurableEnvironment 实现
ConfigurableEnvironment environment = getOrCreateEnvironment();

// 核心代码
switch (this.webApplicationType) {
    case SERVLET:
        // 基于servlet的Web应用程序运行,并应启动嵌入式servlet Web服务器
        return new StandardServletEnvironment();
    case REACTIVE:
        // 响应式Web应用程序运行,并应启动嵌入式响应式Web服务器
        return new StandardReactiveWebEnvironment();
    default:
        return new StandardEnvironment();
}

Environment的结构

image-20230925202804163

// 抽象类的构造方法中会通过模板方法的方式调用 customizePropertySources方法,在不同的子类实现中,会初始化不同的配置源
protected void customizePropertySources(MutablePropertySources propertySources){}
public AbstractEnvironment() {
    customizePropertySources(this.propertySources);
}

// org.springframework.core.env.StandardEnvironment
// 这个里面会添加systemEnvironment(系统变量),systemProperties(系统属性)两个配置源

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(
        new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
    propertySources.addLast(
        new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

//org.springframework.web.context.support.StandardServletEnvironment
//这个里面会添加servletContextInitParams(Servlet上下文参数),servletConfigInitParams(Servlet配置参数),jndiProperties三个配置源

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
    propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
    if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
        propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
    }
    super.customizePropertySources(propertySources);
}

二、配置环境变量

// org.springframework.boot.SpringApplication#configureEnvironment
configureEnvironment(environment, applicationArguments.getSourceArgs());

添加转换服务

//  添加转换服务
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService) conversionService);
}

// 使用适用于大多数Spring Boot应用程序的格式化程序和转换器配置给定的FormatterRegister

public static void configure(FormatterRegistry registry) {
    //添加各种默认的转换器,具体作用后续再研究
    DefaultConversionService.addDefaultConverters(registry);
    DefaultFormattingConversionService.addDefaultFormatters(registry);
    addApplicationFormatters(registry);
    addApplicationConverters(registry);
}

配置属性源

此处会添加默认配置和命令行配置源

configurePropertySources(environment, args);

// 添加默认配置属性
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
    sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
}

// 添加命令行配置属性
if (this.addCommandLineProperties && args.length > 0) {
    String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
    if (sources.contains(name)) {
        PropertySource<?> source = sources.get(name);
        CompositePropertySource composite = new CompositePropertySource(name);
        composite.addPropertySource(
            new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
        composite.addPropertySource(source);
        sources.replace(name, composite);
    }
    else {
        sources.addFirst(new SimpleCommandLinePropertySource(args));
    }
}

添加激活状态配置文件

// 为此应用程序环境配置哪些配置文件处于活动状态(或默认处于活动状态)。在配置文件处理期间,可以通过spring. profile.active属性激活其他配置文件

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
    Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
    profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
org.springframework.boot.context.properties.source.ConfigurationPropertySources#attach
posted @ 2023-09-27 12:49  菜阿  阅读(91)  评论(0编辑  收藏  举报