Spring源码之Environment源码分析.md

Spring源码之Environment源码分析

Environment类体系

在这里插入图片描述

  • PropertyResolver接口:提供属性访问功能,解析${…}

    • containsProperty(String key):返回给定属性键是否可用于解析,即给定键的值是否不是{@code null}。
    • getProperty(String key):返回与给定键关联的属性值,如果无法解析该键,则返回{@code null}
    • getProperty(String key, String defaultValue):如果无法解析该键,则返回默认值
    • T getProperty(String key, Class targetType):返回执行类型
    • T getProperty(String key, Class targetType, T defaultValue):提供默认值
    • String getRequiredProperty(String key) throws IllegalStateException:解析错误抛出异常
    • T getRequiredProperty(String key, Class targetType) throws IllegalStateException:解析错误抛出异常
    • String resolvePlaceholders(String text):解决${…}给定文本中的占位符,用{@link#getProperty}解析的相应属性值替换它们。不带默认值的不可解析占位符将被忽略,并以不变的方式传递
    • String resolveRequiredPlaceholders(String text) throws IllegalArgumentException:抛出异常
  • ConfigurablePropertyResolver:继承自PropertyResolver,主要提供属性类型转换(基于org.springframework.core.convert.ConversionService)功能

    • getConversionService:返回对属性执行类型转换时使用的{@link ConfigurableConversionService}。返回的转换服务的可配置性质允许方便地添加和删除单个{@code Converter}实例:

      * ConfigurableConversionService cs = env.getConversionService();
      * cs.addConverter(new FooConverter());
      
    • setConversionService(ConfigurableConversionService conversionService):设置对属性执行类型转换时要使用的{@link ConfigurableConversionService};

      • 作为完全替换{@code ConversionService}的替代方法,可以考虑通过深入{@link#getConversionService()}并调用{@code#addConverter}等方法来添加或删除单个{@code Converter}实例
    • setPlaceholderPrefix(String placeholderPrefix):设置由此解析器解决程序替换的占位符必须开头的前缀。

    • setPlaceholderSuffix(String placeholderSuffix):设置结束符

    • setValueSeparator(@Nullable String valueSeparator):指定由此替换的占位符之间的分隔字符

      解析程序及其关联的默认值,或者{@code null},如果不应将此类特殊字符作为值分隔符处理。

    • setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders):

      • 设置遇到嵌套在给定属性值中的不可解析占位符时是否引发异常。
      • {@code false}值表示严格解析,即将引发异常。
      • {@code true}值表示不可解析的嵌套占位符应该在其未解析的${…}中传递类型
      • {@link#getProperty(String)}及其变体的实现必须检查此处设置的值,以确定当属性值包含无法解析的占位符时的正确行为。
    • setRequiredProperties(String… requiredProperties):指定必须存在哪些属性,由{@link#validateRequiredProperties()}验证。

    • validateRequiredProperties() throws MissingRequiredPropertiesException:验证{@link#setRequiredProperties}存在并解析为非{@code null}值。@throws-MissingRequiredPropertiesException如果需要属性是不可解析的。

  • Environment接口:继承自PropertyResolver,提供访问和判断profiles的功能。

    • getDefaultProfiles:当没有明确设置活动profile时,返回默认激活的profile
    • acceptsProfiles:返回{@linkplain#getActiveProfiles()active profiles}是否与给定的{@link profiles}谓词匹配
    • getActiveProfiles:如果没有明确指定为活动的Profile,则{@linkplain#getDefaultProfiles()默认配置文件}将自动激活;返回为此环境显式激活的配置文件集。概要文件用于创建要有条件注册的bean定义的逻辑分组,例如基于部署环境;通过将{@linkplain AbstractEnvironment#ACTIVE_Profiles_PROPERTY_NAME“spring.Profiles.ACTIVE”}设置为系统属性或调用
  • ConfigurableEnvironment接口:继承自ConfigurablePropertyResolver和Environment,并且提供设置激活的profile和默认的profile的功能

    • setActiveProfiles(String… profiles)
      • 指定此{@code Environment}的活动Profile。配置文件在容器引导期间进行评估,以确定是否应该向容器注册bean定义
      • 任何现有的活动配置文件都将替换为给定的参数;使用零参数调用以清除当前的活动配置文件集。
      • 使用{@link#addActiveProfile}添加配置文件,同时保留现有集
    • addActiveProfile(String profile)
      • 将配置文件添加到当前激活的配置文件集中。
    • setDefaultProfiles(String… profiles)
      • 如果没有其他配置文件通过{@link#setActiveProfiles}显式激活,则指定默认情况下激活的配置文件集。
    • MutablePropertySources getPropertySources()
      • 以可变形式返回此{@code-Environment}的{@link-PropertySources},允许在解析针对此{@code-Environment}对象的属性时,操作应搜索的{@link-PropertySources}对象集
      • 各种{@link MutablePropertySources}方法,例如
        • {@link MutablePropertySources#addFirst addFirst},
        • {@link MutablePropertySources#addLast addLast},\
        • {@link MutablePropertySources#addBefore addBefore}和
        • {@link MutablePropertySources#addAfter addAfter}
        • 允许对属性源排序进行细粒度控制。例如,这有助于确保某些用户定义的特性源的搜索优先级高于默认特性源,例如系统特性集或系统环境变量集。
  • ConfigurableWebEnvironment接口:继承自ConfigurableEnvironment,并且提供配置Servlet上下文和Servlet参数的功能

    • initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig)

      • 将任何充当占位符的{@linkplain org.springframework.core.env.PropertySource.StubPropertySource StubPropertySource}实例替换为真正的servlet上下文/配置属性源使用给定的参数。

      • @param servletContext{@link servletContext}(不能是{@code null})

        @param servletConfig{@link servletConfig}({@code null}如果不可用)

  • AbstractEnvironment抽象类:实现了ConfigurableEnvironment接口,默认属性和存储容器的定义,并且实现了ConfigurableEnvironment中的方法,并且为子类预留可覆盖了扩展方法。

  • StandardEnvironment:继承自AbstractEnvironment,非Servlet(Web)环境下的标准Environment实现。

  • StandardServletEnvironment:继承自StandardEnvironment,Servlet(Web)环境下的标准Environment实现

    • StandardEnvironment#customizePropertySources

    • ConfigurableWebEnvironment#initPropertySources

Environment的存储容器

Environment的静态属性和存储容器都是在AbstractEnvironment中定义的,ConfigurableWebEnvironment接口提供的getPropertySources()方法可以获取到返回的MutablePropertySources实例,然后添加额外的PropertySource。实际上,Environment的存储容器就是org.springframework.core.env.PropertySource的子类集合,AbstractEnvironment中使用的实例是org.springframework.core.env.MutablePropertySources,下面看下PropertySource的源码:

public abstract class PropertySource<T> {

 protected final Log logger = LogFactory.getLog(getClass());

 protected final String name;

 protected final T source;

 public PropertySource(String name, T source) {
 Assert.hasText(name, "Property source name must contain at least one character");
 Assert.notNull(source, "Property source must not be null");
 this.name = name;
 this.source = source;
 }

 @SuppressWarnings("unchecked")
 public PropertySource(String name) {
 this(name, (T) new Object());
 }

 public String getName() {
 return this.name;
 }

 public T getSource() {
 return this.source;
 } 

 public boolean containsProperty(String name) {
 return (getProperty(name) != null);
 } 

 @Nullable
 public abstract Object getProperty(String name); 

 @Override
 public boolean equals(Object obj) {
 return (this == obj || (obj instanceof PropertySource &&
 ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) obj).name)));
 } 

 @Override
 public int hashCode() {
 return ObjectUtils.nullSafeHashCode(this.name);
 } 
//省略其他方法和内部类的源码 
}
  • 源码相对简单,预留了一个getProperty抽象方法给子类实现,重点需要关注的是覆写了的equals和hashCode方法,实际上只和name属性相关,这一点很重要,说明一个PropertySource实例绑定到一个唯一的name,这个name有点像HashMap里面的key,部分移除、判断方法都是基于name属性
  • PropertySource的最常用子类
    • MapPropertySource:source指定为Map实例的PropertySource实现。
    • PropertiesPropertySource:source指定为Map实例的PropertySource实现,内部的Map实例由Properties实例转换而来。
    • ResourcePropertySource:继承自PropertiesPropertySource,source指定为通过Resource实例转化为Properties再转换为Map实例。
    • StubPropertySource:PropertySource的一个内部类,source设置为null,实际上就是空实现。
    • ComparisonPropertySource:继承自ComparisonPropertySource,所有属性访问方法强制抛出异常,作用就是一个不可访问属性的空实现。

AbstractEnvironment中的属性定义

public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";

private final Set<String> activeProfiles = new LinkedHashSet<>();

private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());

private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
  • 上面的propertySources(MutablePropertySources类型)属性就是用来存放PropertySource列表的,PropertySourcesPropertyResolver是ConfigurablePropertyResolver的实现,默认的profile就是字符串default
  • MutablePropertySources是PropertySources的子类,它提供了get(String name)、addFirst、addLast、addBefore、addAfter、remove、replace等便捷方法,方便操作propertySourceList集合的元素

重要的三个方法

/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
        //事件监控
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
        //获取spring,facories中的监听器变量,args为指定的参数数组,默认为当前类SpringApplication
        //1.获取并启动监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
            //包装了一个DefaultApplicationArguments把我们启动的参数放入类中
            //这个类包装了我们启动的main函数上面的String[] args,在我们启动jar包的时候我们可以给args赋值,这个值我们同样传到后面的run方法中并做了
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //2.准备了一个Environment:构造容器环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            //3.configureIgnoreBeanInfo放入需要ignore的bean
			configureIgnoreBeanInfo(environment);
            //printBanner打印Banner(SpringBoot启动时打印的logo)
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
            //4.实例化SpringBootExceptionReporter.class,用来支持关于启动的错误
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            //5.启动容器
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //6.刷新容器
			refreshContext(context);
            //7.刷新容器后的扩展接口
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

#DefaultApplicationArguments

public DefaultApplicationArguments(String... args) {
		Assert.notNull(args, "Args must not be null");
		this.source = new Source(args);
		this.args = args;
	}
	
//Source 类是DefaultApplicationArguments的内部类继承了 SimpleCommandLinePropertySource 类构造方法直接调用了super(args);所以我们只需要看 SimpleCommandLinePropertySource 类的处理流程就行了:

private static class Source extends SimpleCommandLinePropertySource {

		Source(String[] args) {
			super(args);
		}

		@Override
		public List<String> getNonOptionArgs() {
			return super.getNonOptionArgs();
		}

		@Override
		public List<String> getOptionValues(String name) {
			return super.getOptionValues(name);
		}

	}

//super 类的构造方法同样调用了父类 CommandLinePropertySource 的构造方法,并传入处理之后的对象,我们来看下new SimpleCommandLineArgsParser().parse(args)是如何处理args的:
public SimpleCommandLinePropertySource(String... args) {
		super(new SimpleCommandLineArgsParser().parse(args));
	}

//spring有关的配置:   --spring.profiles.active=dev
//代码非常简单,如果已--开头则进入处理拿到name和value,并放入commandLineArgs中并放回 CommandLineArgs 对象.之后调用父类
//CommandLinePropertySource 的构造方法:
public CommandLineArgs parse(String... args) {
		CommandLineArgs commandLineArgs = new CommandLineArgs();
		for (String arg : args) {
            //如果已--开头则进入处理拿到name和value
			if (arg.startsWith("--")) {
				String optionText = arg.substring(2, arg.length());
				String optionName;
				String optionValue = null;
                //处理拿到name和value
				if (optionText.contains("=")) {
					optionName = optionText.substring(0, optionText.indexOf('='));
					optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
				}
				else {
					optionName = optionText;
				}
				if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
					throw new IllegalArgumentException("Invalid argument syntax: " + arg);
				}
                //放入commandLineArgs中并返回 CommandLineArgs 对象
				commandLineArgs.addOptionArg(optionName, optionValue);
			}
			else {
				commandLineArgs.addNonOptionArg(arg);
			}
		}
		return commandLineArgs;
	}

//调用父类CommandLinePropertySource 的构造方法,其中COMMAND_LINE_PROPERTY_SOURCE_NAME是上面写死的成员变量 public static final String COMMAND_LINE_PROPERTY_SOURCE_NAME = "commandLineArgs";
public CommandLinePropertySource(T source) {
		super(COMMAND_LINE_PROPERTY_SOURCE_NAME, source);
	}

//然后还是调用父类的构造方法 EnumerablePropertySource,然后直接调用父类PropertySource 的构造方法:给name和source赋值
public PropertySource(String name, T source) {
		Assert.hasText(name, "Property source name must contain at least one character");
		Assert.notNull(source, "Property source must not be null");
		this.name = name;
		this.source = source;
	}

#prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		//根据应用程序的类型创建对应的环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
    	//获取到启动参数,通过参数配置环境
		configureEnvironment(environment, applicationArguments.getSourceArgs());
    	//这一步往environment中添加configurationProperties为前缀的source
		ConfigurationPropertySources.attach(environment);
        //发布环境已准备的事件(重点方法):这是第二次发布事件,启动相应的监听器,其中一个重要的监听器ConfigApplicationListener就是加载项目配置文件的监听器
		listeners.environmentPrepared(environment);
    	//将环境绑定到应用程序当中
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

在这里插入图片描述

#getOrCreateEnvironment
public enum WebApplicationType{
    //不需要再web容器的环境下运行
    NONE;
    //基于servlet的web项目
    SERVLET;
    //spring5开始的新特性
    REACTIVE;
}
static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
            && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
            && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}
由于ClassLoader都是空,所以直接返回一个WebApplicationType.SERVLET,然后由getOrCreateEnvironment方法创建一个 StandardServletEnvironment 对象

//environment已经被设置了servlet类型,所以这里创建StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
    //如果有environment则返回,如果没有就创建
    if (this.environment != null) {
        return this.environment;
    }
    //根据应用的类型选择环境,这里会创建一个 StandardServletEnvironment 对象
    //webApplicationType的赋值是在创建SpringApplication对象中调用 WebApplicationType.deduceFromClasspath() 方法实现的
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
    }
}
//在创建 StandardServletEnvironment 时,因为没有构造函数,所以直接调用父类构造方法,而他的父类 StandardEnvironment 也没有构造方法,继续调用父类AbstractEnvironment的构造方法,AbstractEnvironment的构造方法会去执行customizePropertySources
//customizePropertySources:这个方法在 StandardEnvironment 和 StandardServletEnvironment 中都有实现
public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
	}

StandardServletEnvironment:
@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);
}
StandardEnvironment:
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
    propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
    propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

//最后的效果是里面有四个值分别是:propertySources里面有四个key:servletConfigInitParams,servletContextInitParams,
//systemEnvironment,systemProperties,前两个key的value是一个object();systemProperties 的value是System.getProperties();加载了一堆系统变量

 
  • 基于上面的这个思想我们可以自定义环境
下面这个自定义Environment主要是加载自定义配置文件。注意这里没有任何的实际的意义 仅仅演示。因为Springboot为我们提供了更简单的方式去加载自定义配置文件,仅仅是为了熟悉流程
在项目resources目录下面新建一个customize.yml

coledy:
    account: xxxxxx

自定义Environment我们只需要继承StandardEnvironment或者其子类即可。
由于我们现在是web环境所以我选择继承StandardServletEnvironment@Slf4j
public class CustomEnvironment extends StandardServletEnvironment {
  @Override
  protected void customizePropertySources(MutablePropertySources propertySources) {
    //这行代码不能少 父类也需要加载一些环境信息 例如StandardServletEnvironment就需要去加载
    //servletContext参数和servletConfig参数 
    super.customizePropertySources(propertySources);
    //这里我们使用默认的ResourceLoad去加载类路径下的配置文件
    Resource resource = new DefaultResourceLoader().getResource("classpath:customize.yml");
    try {
    //这里使用yml解析器解析 加载的Resource 
      List<PropertySource<?>> customYml = new YamlPropertySourceLoader().load("customize_yml", resource);
      for (PropertySource<?> p : customYml){
        propertySources.addLast(p);
      }
    }catch (IOException e){
        log.error("加載custom.yml配置文件異常!!!");
    }
  }
}

由于是自定义Environment所以我们启动类需要修改一下
@SpringBootApplication
public class SpringbootStudyApplication{
  public static void main(String[] args) {
    SpringApplication application = new SpringApplicationBuilder(SpringbootStudyApplication.class).application();
    //这里需要我们手动设置一下自定义变量的实例
    application.setEnvironment(new CustomEnvironment());
    ApplicationContext context = application.run(args);
    ConfigurableEnvironment environment = context.getBean(ConfigurableEnvironment.class);
    System.out.println(environment.getProperty("coledy.account"));
  }
}

我们看到自定义一个Environment流程很简单。
可是问题是刚刚我们提到的 web环境变量 系统环境变量 命令行参数 默认的application.yml 文件是什么时候加载的?我们先不着急回答这个问题 先看一下刚刚的 propertySources.addLast 这一行代码。我们把自定义的 customize.yml手动添加到了一个集合中 结果我们就可以在容器中拿到配置的信息
    
    
走一下原来的流程
SpringApplication#getOrCreateEnvironment会返回一个StandardServletEnvironment
因为StandardServletEnvironment继承StandardEnvironmentStandardEnvironment继承了AbstractEnvironment,肯定要先加载AbstractEnvironment的构造方法,AbstractEnvironment的构造方法里面又会调用customizePropertySources方法,回去直接调用StandardServletEnvironment的customizePropertySources

@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));
		}
		//继续去调用StandardEnvironment的实现方法加载该类里面的属性
		super.customizePropertySources(propertySources);
	}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aXttIkhZ-1657260592404)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1652568169197.png)]

#configureEnvironment()

​ 配置环境的一些配置信息,设置转换器用作参数的转换

protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
    	//args为:--spring.profiles.active=prod
        //his.addConversionService == true,所以会调用 ApplicationConversionService.getSharedInstance();方法:
		if (this.addConversionService) {
            //new 一个ApplicationConversionService当做sharedInstance并返回,
            //所以上面的 ConversionService 的实际的对象是 ApplicationConversionService
            //然后把conversionService强转成 ConfigurableConversionService 并赋值给environment的           	                 //setConversionService方法.因为 ConfigurableConversionService是一个继承 
            //ApplicationConversionService 的空接口所以可以直接强转,之后调用configurePropertySources方法继续处理
			ConversionService conversionService = ApplicationConversionService
					.getSharedInstance();
			environment.setConversionService(
					(ConfigurableConversionService) conversionService);
		}
    	//将args封装成了SimpleCommandLinePropertySource并加入到了environment中
		configurePropertySources(environment, args);
    	//根据启动参数激活了相应的配置文件(例如在Program arguments中配置 )
		configureProfiles(environment, args);
	}

#configurePropertySources:
//参数args是通过上面传进来的参数
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    	
    	//environment的propertySources在构造StandardServletEnvironment时赋值,
        //里面有四个值分别是:servletConfigInitParams,servletContextInitParams,
        //systemEnvironment,systemProperties,因为我们启动没有加参数,所以这个方法做任何处理,
        //如果加入了参数会走下面的if把 COMMAND_LINE_PROPERTY_SOURCE_NAME为key,args为value的          					//SimpleCommandLinePropertySource 放入composite并把composite放入sources中
    	
		MutablePropertySources sources = environment.getPropertySources();
		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));
			}
		}
	}


#configureProfiles
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
    	//profile为空
		Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
        //调用了environment.getActiveProfiles()方法:此时profiles为prod
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    	//设置environment的activeProfiles为prod
		environment.setActiveProfiles(StringUtils.toStringArray(profiles));
	}


@Override
	public String[] getActiveProfiles() {
		return StringUtils.toStringArray(doGetActiveProfiles());
	}


protected Set<String> doGetActiveProfiles() {
		synchronized (this.activeProfiles) {
			if (this.activeProfiles.isEmpty()) {
				String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
				if (StringUtils.hasText(profiles)) {
					setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				}
			}
			return this.activeProfiles;
		}
	}

    //调用getProperty方法获取profiles
    @Override
	@Nullable
	public String getProperty(String key) {
		return this.propertyResolver.getProperty(key);
	}

#propertyResolver
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
在成员变量中直接创建了PropertySourcesPropertyResolver 的对象,传入propertySources,这个propertySources就是我们之前创建
severlet对象时赋值的propertySources,里面有四个值,但是没有ACTIVE_PROFILES_PROPERTY_NAME,所以获取的是空.
这里有个问题,ACTIVE_PROFILES_PROPERTY_NAME==spring.profiles.active,我们在spring的配置文件中会使用这个key配置读取得环境但是现在并没有读取出来,这个配置是在后面读取的(ConfigFileApplicationListener).
  • 走完configurePropertySources(environment, args)和configureProfiles(ConfigurableEnvironment environment, String[] args)

在这里插入图片描述

  • 走完configureProfiles
#environmentPrepared()
  • 发布环境配置的事件,根据环境读取到对应的配置文件
//通过事件广播器,发布应用环境准备的事件
public void environmentPrepared(ConfigurableEnvironment environment) {
    	//创建了 ApplicationEnvironmentPreparedEvent 对象
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}

public ApplicationContextInitializedEvent(SpringApplication application, String[] args,
			ConfigurableApplicationContext context) {
        //先调用了父类(SpringApplicationEvent)构造方法,然后把environment赋值给成员变量
		super(application, args);
		this.context = context;
	}

#EventObject的构造方法
//赋值了source,同样的source是 SpringApplication 对象,同样的调用multicastEvent方法,同样获取Executor,同样invoke,就不在赘述了值得注意的是,这里执行的listener是为environment赋值使用的,例如前面我们提到的读取spring.profiles.active配置,就是在ConfigFileApplicationListener 中实现的
 public EventObject(Object source) {
        if (source == null) {
            throw new IllegalArgumentException("null source");
        } else {
            this.source = source;
        }
    }

#multicastEvent

public void multicastEvent(ApplicationEvent event) {
    //第一个参数是事件对象,第二个参数,根据事件解析出对应的事件类型对象(ResolvableType)
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }

onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event)方法
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
    //获取到对应的监听器,其中使用了缓存的方式将对应的事件类型跟监听器缓存起来,便于后续获取;其中使用了 GenericApplicationListenerAdapter 适配器的方式来提供给不同的监听器用来进行适配
        Iterator var4 = this.getApplicationListeners(event, type).iterator();

        while(var4.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var4.next();
            Executor executor = this.getTaskExecutor();
            if (executor != null) {
                //如果设置了线程池,就使用异步的方式进行执行
                executor.execute(() -> {
                    this.invokeListener(listener, event);
                });
            } else {
                //执行监听器执行的监听器为:ConfigFileApplicationListener
                this.invokeListener(listener, event);
            }
        }

    }

在这里插入图片描述

  • 主要来看一下ConfigFileApplicationListener,该监听器非常核心,主要用来处理项目配置。项目中的 properties 和yml文件都是其内部类所加载

#ConfigFileApplicationListener

@Override
	public void onApplicationEvent(ApplicationEvent event) {
        显然event就是ApplicationEnvironmentPreparedEvent,所以会进入下面这个if
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent(
					(ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}

#onApplicationEnvironmentPreparedEvent

private void onApplicationEnvironmentPreparedEvent(
			ApplicationEnvironmentPreparedEvent event) {
    //方法首先调用loadPostProcessors方法做一些处理:加载 EnvironmentPostProcessor 的实现类
		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
    //将 ConfigFileApplicationListener 添加到处理链当中。配置文件的读取也是由 ConfigFileApplicationListener进行处理
		postProcessors.add(this);
		AnnotationAwareOrderComparator.sort(postProcessors);
		for (EnvironmentPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessEnvironment(event.getEnvironment(),
					event.getSpringApplication());
		}
	}

  • 目前加载出来的对象如下图
    在这里插入图片描述

#ConfigFileApplicationListener:postProcessEnvironment

//当前方法调用了内部方法 addPropertySources(environment, application.getResourceLoader());
@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
	}

//其中创建了 Loder对象,,并且调用了load() 方法
//从字面上看第一步加入一个什么东西到environment中,然后在load个什么东西具体加入和load的内容是什么呢?
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
		new Loader(environment, resourceLoader).load();
	}

#addToEnvironment
//这个方法特别简单,创建了个RandomValuePropertySource的类然后放在environment中的propertySources里SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME
//key的后面,至于RandomValuePropertySource对象的创建,不用看了特别简单就是获取一个随机数.
//经过这样的处理environment中的source里加了一个对象:RandomValuePropertySource {name='random',value=随机数}
public static void addToEnvironment(ConfigurableEnvironment environment) {	environment.getPropertySources().addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
				new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME));
		logger.trace("RandomValuePropertySource add to Environment");
	}


在这里插入图片描述

#loader
//把environment中的属性赋值一份放在Loader里,resourceLoader就是 DefaultResourceLoader ,获取的是当前线程的classLoader
//然后propertySourceLoaders还是调用loadFactories方法获取对象,获取完的对象 有两个:
//PropertiesPropertySourceLoader和YamlPropertySourceLoader
//一个负责处理.properties一个负责处理.yml
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
			this.environment = environment;
			this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
			this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
			this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
					getClass().getClassLoader());
		}

void load() {
			FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
					(defaultProperties) -> {
						this.profiles = new LinkedList<>();
						this.processedProfiles = new LinkedList<>();
						this.activatedProfiles = false;
						this.loaded = new LinkedHashMap<>();
                        //初始化环境,会将环境中的默认环境添加到this.profiles当中
                        //初始会有两个元素一个是空的,一个"default"
						initializeProfiles();
                        //取出环境进行处理
						while (!this.profiles.isEmpty()) {
                            //第一次循环profiles是null不会走第一个if
							Profile profile = this.profiles.poll();
							if (isDefaultProfile(profile)) {
								addProfileToEnvironment(profile.getName());
							}
							load(profile, this::getPositiveProfileFilter,
									addToLoaded(MutablePropertySources::addLast, false));
							this.processedProfiles.add(profile);
						}
						load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
						addLoadedPropertySources();
						applyActiveProfiles(defaultProperties);
					});
		}



#initializeProfiles
private void initializeProfiles() {
			// The default profile for these purposes is represented as null. We add it
			// first so that it is processed first and has lowest priority.
			this.profiles.add(null);
			Set<Profile> activatedViaProperty = getProfilesFromProperty(ACTIVE_PROFILES_PROPERTY);
			Set<Profile> includedViaProperty = getProfilesFromProperty(INCLUDE_PROFILES_PROPERTY);
			List<Profile> otherActiveProfiles = getOtherActiveProfiles(activatedViaProperty, includedViaProperty);
			this.profiles.addAll(otherActiveProfiles);
			// Any pre-existing active profiles set via property sources (e.g.
			// System properties) take precedence over those added in config files.
			this.profiles.addAll(includedViaProperty);
			addActiveProfiles(activatedViaProperty);
    		//判断profiles的size是否等于1,进入for循环处理
			if (this.profiles.size() == 1) { // only has null profile
                //然后for循环会创建Profile对象
				for (String defaultProfileName : this.environment.getDefaultProfiles()) {
					Profile defaultProfile = new Profile(defaultProfileName, true);
					this.profiles.add(defaultProfile);
				}
			}
		}

//这段代码首先在profiles中添加一个null,然后调用 getProfilesFromProperty
//从environment中的resouce获取 ACTIVE_PROFILES_PROPERTY(spring.profiles.active)和INCLUDE_PROFILES_PROPERTY(spring.profiles.include)
//因为environment中没有所以直接返回一个空的set集合
private Set<Profile> getProfilesFromProperty(String profilesProperty) {
			if (!this.environment.containsProperty(profilesProperty)) {
				return Collections.emptySet();
			}
			Binder binder = Binder.get(this.environment);
			Set<Profile> profiles = getProfiles(binder, profilesProperty);
			return new LinkedHashSet<>(profiles);
		}

//调用了environment.getActiveProfiles()方法获取,这个方法在之前研究过,获取不到任何东西,所以返回依旧是null,这些操作之后profiles内的对象依然只有一个null
private List<Profile> getOtherActiveProfiles(Set<Profile> activatedViaProperty,
				Set<Profile> includedViaProperty) {
			return Arrays.stream(this.environment.getActiveProfiles()).map(Profile::new).filter(
					(profile) -> !activatedViaProperty.contains(profile) && !includedViaProperty.contains(profile))
					.collect(Collectors.toList());
		}

//addActiveProfiles因为profiles是empty的,所以直接返回,,没有记日志
void addActiveProfiles(Set<Profile> profiles) {
			if (profiles.isEmpty()) {
				return;
			}
			if (this.activatedProfiles) {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Profiles already activated, '" + profiles + "' will not be applied");
				}
				return;
			}
			this.profiles.addAll(profiles);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Activated activeProfiles " + StringUtils.collectionToCommaDelimitedString(profiles));
			}
			this.activatedProfiles = true;
			removeUnprocessedDefaultProfiles();
		}

protected Set<String> doGetDefaultProfiles() {
		synchronized (this.defaultProfiles) {
            //doGetDefaultProfiles首先判断了this.defaultProfiles.equals(getReservedDefaultProfiles(),this.defaultProfiles在成员变量里直接赋值了:
//private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
//所以肯定是equals的
			if (this.defaultProfiles.equals(getReservedDefaultProfiles())) {
                //,然后调用getProperty方法直接返回了environment中的propertyResolver中的spring.profiles.default为key的value值,返回的依旧是空,然后方法直接返回defaultProfiles即default,然后for循环会创建Profile对象
				String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
				if (StringUtils.hasText(profiles)) {
					setDefaultProfiles(StringUtils.commaDelimitedListToStringArray(
							StringUtils.trimAllWhitespace(profiles)));
				}
			}
			return this.defaultProfiles;
		}
	}


protected Set<String> getReservedDefaultProfiles() {
		return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
	}

#加载配置文件中的信息

private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
    		//获取到所有的配置文件的路径:初始化时有4个文件的路径
    		//file:./config/
    		//file:./
    		//classpath:/config/
    		//classpath:/
			getSearchLocations().forEach((location) -> {
                //判断格式是否正确以/结果
				boolean isFolder = location.endsWith("/");
                //获取项目名
				Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
                //根据项目名+文件前缀+环境遍历循环,后面会进行拼接
                //
				names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
			});
		}

//首先getSearchLocations获取所有前缀
//一串代码下来获取的是DEFAULT_SEARCH_LOCATIONS("classpath:/,classpath:/config/,file:./,file:./config/")
//在我们之后读取配置文件时这些前缀会帮助我们拼接地址
private Set<String> getSearchLocations() {
    if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
        return getSearchLocations(CONFIG_LOCATION_PROPERTY);
    }
    Set<String> locations = getSearchLocations(
            CONFIG_ADDITIONAL_LOCATION_PROPERTY);
    locations.addAll(
            asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
                    DEFAULT_SEARCH_LOCATIONS));
    return locations;
}

private Set<String> getSearchLocations(String propertyName) {
    Set<String> locations = new LinkedHashSet<>();
    if (this.environment.containsProperty(propertyName)) {
        for (String path : asResolvedSet(
                this.environment.getProperty(propertyName), null)) {
            if (!path.contains("$")) {
                path = StringUtils.cleanPath(path);
                if (!ResourceUtils.isUrl(path)) {
                    path = ResourceUtils.FILE_URL_PREFIX + path;
                }
            }
            locations.add(path);
        }
    }
    return locations;
}
  • 返回结果

在这里插入图片描述

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
				DocumentConsumer consumer) {
            //因为StringUtils.hasText(name)返回true,不会走下面的if
			if (!StringUtils.hasText(name)) {
				for (PropertySourceLoader loader : this.propertySourceLoaders) {
					if (canLoadFileExtension(loader, location)) {
						load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
						return;
					}
				}
				throw new IllegalStateException("File extension of config file location '" + location
						+ "' is not known to any PropertySourceLoader. If the location is meant to reference "
						+ "a directory, it must end in '/'");
			}
			Set<String> processed = new HashSet<>();
    		//获取propertySourceLoaders一个个处理,propertySourceLoaders就是之前获取的yml和properties的loader
			for (PropertySourceLoader loader : this.propertySourceLoaders) {
                //for循环中获取loader.getFileExtensions()返回{ "properties", "xml" }和{ "yml", "yaml" }
				for (String fileExtension : loader.getFileExtensions()) {
					if (processed.add(fileExtension)) {
                        //加载对应路径的配置文件信息
						loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,consumer);
					}
				}
			}
		}


  • this.propertySourceLoaders

在这里插入图片描述

  • loader.getFileExtensions()
    在这里插入图片描述
loadForFileExtension
loader:PropertiesPropertySourceLoader
perfix:"file:/config/application"
fileExtension:".properties"
Profile:null
    
private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
				Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
			DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
    		//第一次profile为null
			if (profile != null) {
				// classpath:/config/application-default.yml
				String profileSpecificFile = prefix + "-" + profile + fileExtension;
				load(loader, profileSpecificFile, profile, defaultFilter, consumer);
				load(loader, profileSpecificFile, profile, profileFilter, consumer);
				// Try profile specific sections in files we've already processed
				for (Profile processedProfile : this.processedProfiles) {
					if (processedProfile != null) {
						String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
                        //和下面的load调用的是同一个方法
						load(loader, previouslyLoaded, profile, profileFilter, consumer);
					}
				}
			}
			//加载其他application-test,application-prod...没有用到的配置文件
			load(loader, prefix + fileExtension, profile, profileFilter, consumer);
		}

#load

private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter,
				DocumentConsumer consumer) {
			try {
                //获取根据classpath:/config/application.yml得到resouce
				Resource resource = this.resourceLoader.getResource(location);
				if (resource == null || !resource.exists()) {
					if (this.logger.isTraceEnabled()) {
						StringBuilder description = getDescription("Skipped missing config ", location, resource,
								profile);
						this.logger.trace(description);
					}
					return;
				}
                //resource.getFilename():application.yml
                //StringUtils.getFilenameExtension(resource.getFilename()):yml
				if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
					if (this.logger.isTraceEnabled()) {
						StringBuilder description = getDescription("Skipped empty config extension ", location,
								resource, profile);
						this.logger.trace(description);
					}
					return;
				}
                //name:applicationConfig: [classpath:/config/application.yml]
                //只有在拼接成classpath:application.properties时才能真正加载上面的代码:
				String name = "applicationConfig: [" + location + "]";
                //调用loadDocuments方法加载配置文件
				List<Document> documents = loadDocuments(loader, name, resource);
				if (CollectionUtils.isEmpty(documents)) {
					if (this.logger.isTraceEnabled()) {
						StringBuilder description = getDescription("Skipped unloaded config ", location, resource,
								profile);
						this.logger.trace(description);
					}
					return;
				}
				List<Document> loaded = new ArrayList<>();
                //直接使用PropertiesLoaderUtils获取了properties中所有的配置信息然后转换成document对象返回
                //返回到load方法继续执行
				for (Document document : documents) {
					if (filter.match(document)) {
                        //直接循环调用addActiveProfiles和addIncludedProfiles赋值了profiles和 include
						//返回最初的load:
						addActiveProfiles(document.getActiveProfiles());
						addIncludedProfiles(document.getIncludeProfiles());
						loaded.add(document);
					}
				}
				Collections.reverse(loaded);
				if (!loaded.isEmpty()) {
					loaded.forEach((document) -> consumer.accept(profile, document));
					if (this.logger.isDebugEnabled()) {
						StringBuilder description = getDescription("Loaded config file ", location, resource, profile);
						this.logger.debug(description);
					}
				}
			}
			catch (Exception ex) {
				throw new IllegalStateException("Failed to load property source from location '" + location + "'", ex);
			}
		}

 
#loadDocuments
//loader:properties或者yml
//name:applicationConfig: [classpath:/application.properties]
//resource:class path resource [application.properties]
private List<Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource)
				throws IOException {
   //先从cache中获取documents,如果没有就loader.load(name, resource)读取,这是初始化肯定在cache中没有数据
			DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
			List<Document> documents = this.loadDocumentsCache.get(cacheKey);
			if (documents == null) {
                //则调用loader.load
				List<PropertySource<?>> loaded = loader.load(name, resource);
                //将读取到的List<PropertySource<?>>转为documents
				documents = asDocuments(loaded);
                //加入到缓存里面
				this.loadDocumentsCache.put(cacheKey, documents);
			}
			return documents;
		}


//PropertiesPropertySourceLoader
//name:applicationConfig: [classpath:/application.properties]
//resource:class path resource [application.properties]
@Override
public List<PropertySource<?>> load(String name, Resource resource)
        throws IOException {
    Map<String, ?> properties = loadProperties(resource);
    if (properties.isEmpty()) {
        return Collections.emptyList();
    }
    return Collections
            .singletonList(new OriginTrackedMapPropertySource(name, properties));
}

#loadProperties
private Map<String, ?> loadProperties(Resource resource) throws IOException {
        //application.properties
		String filename = resource.getFilename();
		if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
			return (Map) PropertiesLoaderUtils.loadProperties(resource);
		}
		return new OriginTrackedPropertiesLoader(resource).load();
	}

//构建OriginTrackedPropertiesLoader然后执行其load方法 new OriginTrackedPropertiesLoader(resource).load()
Map<String, OriginTrackedValue> load(boolean expandLists) throws IOException {
    //将resource传入构建CharacterReader
    //从源资源中读取字符,负责跳过注释、处理多行值和跟踪{@code'\\'}转义。
		try (CharacterReader reader = new CharacterReader(this.resource)) {
			Map<String, OriginTrackedValue> result = new LinkedHashMap<>();
			StringBuilder buffer = new StringBuilder();
            //while循环,读取配置文件中的值
			while (reader.read()) {
				String key = loadKey(buffer, reader).trim();
				if (expandLists && key.endsWith("[]")) {
					key = key.substring(0, key.length() - 2);
					int index = 0;
					do {
						OriginTrackedValue value = loadValue(buffer, reader, true);
						put(result, key + "[" + (index++) + "]", value);
						if (!reader.isEndOfLine()) {
							reader.read();
						}
					}
					while (!reader.isEndOfLine());
				}
				else {
					OriginTrackedValue value = loadValue(buffer, reader, false);
					put(result, key, value);
				}
			}
            //返回读取的数据
			return result;
		}
	}

//YamlPropertySourceLoader
@SuppressWarnings({ "unchecked", "rawtypes" })
private Map<String, ?> loadProperties(Resource resource) throws IOException {
    String filename = resource.getFilename();
    if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
        return (Map) PropertiesLoaderUtils.loadProperties(resource);
    }
    return new OriginTrackedPropertiesLoader(resource).load();
}
  • resource:
    在这里插入图片描述
    #addProfileToEnvironment
//因为现在environment中还没有activeProfile,所以调用this.environment.addActiveProfile(profile);方法把profiles放入environment中
private void addProfileToEnvironment(String profile) {
			for (String activeProfile : this.environment.getActiveProfiles()) {
				if (activeProfile.equals(profile)) {
					return;
				}
			}
			this.environment.addActiveProfile(profile);
		}

//调用 doGetActiveProfiles 方法,前面知道返回空,然后把profile加入profiles中,
@Override
	public void addActiveProfile(String profile) {
		if (logger.isDebugEnabled()) {
			logger.debug("Activating profile '" + profile + "'");
		}
		validateProfile(profile);
		doGetActiveProfiles();
		synchronized (this.activeProfiles) {
			this.activeProfiles.add(profile);
		}
	}


private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
				Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
			DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
    		这一次传入的profile不为空,所以会走loadForFileExtension的
			if (profile != null) {
				// Try profile-specific file & profile section in profile file (gh-340)
				String profileSpecificFile = prefix + "-" + profile + fileExtension;
				load(loader, profileSpecificFile, profile, defaultFilter, consumer);
				load(loader, profileSpecificFile, profile, profileFilter, consumer);
				// Try profile specific sections in files we've already processed
				for (Profile processedProfile : this.processedProfiles) {
					if (processedProfile != null) {
						String previouslyLoaded = prefix + "-" + processedProfile + fileExtension;
						load(loader, previouslyLoaded, profile, profileFilter, consumer);
					}
				}
			}
			// Also try the profile-specific section (if any) of the normal file
			load(loader, prefix + fileExtension, profile, profileFilter, consumer);
		}


//这段代码把loaded中的变量放入environment.getPropertySources()中,放入了两个:application-dvep.properties和 application.properties
private void addLoadedPropertySources() {
			MutablePropertySources destination = this.environment.getPropertySources();
			List<MutablePropertySources> loaded = new ArrayList<>(this.loaded.values());
			Collections.reverse(loaded);
			String lastAdded = null;
			Set<String> added = new HashSet<>();
    		//遍历loaded
			for (MutablePropertySources sources : loaded) {
                //遍历sources
				for (PropertySource<?> source : sources) {
					if (added.add(source.getName())) {
                        //添加到destination中
						addLoadedPropertySource(destination, lastAdded, source);
						lastAdded = source.getName();
					}
				}
			}
		}

//代码执行到这里,整个 ConfigFileApplicationListener 类已经全部完成加载,现在我们总结一下这个监听器都做了什么:
//总的来说就是加载配置文件.
//但是健在的流程是获取所有的loader包括properties和yml的loader,然后在加载default的配置文件名获得application和default的//配置文件路径获得
//classpath:/,classpath:/config/,file:./,file:./config/ 文件路径,遍历拼装配置文件路径并获取配置文件里的内容,把他们放入environment中

版本2.4.0-3.0.0读取配置文件使用的是ConfigDataEnvironmentPostProcessor 实现了EnvironmentPostProcessor

#postProcessEnvironment

@Override
	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		postProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());
	}

	void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
			Collection<String> additionalProfiles) {
		try {
			this.logger.trace("Post-processing environment to add config data");
			resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
			getConfigDataEnvironment(environment, resourceLoader, additionalProfiles).processAndApply();
		}
		catch (UseLegacyConfigProcessingException ex) {
			this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]",
					ex.getConfigurationProperty()));
			configureAdditionalProfiles(environment, additionalProfiles);
			postProcessUsingLegacyApplicationListener(environment, resourceLoader);
		}
	}

ConfigDataEnvironment#processAndApply

ConfigDataEnvironment
包装{@link ConfigurableEnvironment},可用于导入和应用{@link ConfigData}。

通过包装Spring{@link Environment}中的属性源并添加初始位置集,配置{@link ConfigDataEnvironmentContributors}的初始集。

初始位置可以通过{@link#LOCATION_PROPERTY}、{@value#ADDITIONAL_LOCATION_PROPERTY}和{@value#IMPORT_PROPERTY}属性来影响。
如果没有设置显式属性,将使用{@link#DEFAULT _SEARCH _LOCATIONS}。

   /**
	 *使用的属性将覆盖导入的位置。
	 */
	static final String LOCATION_PROPERTY = "spring.config.location";

	/**
	 * 属性,用于提供要导入的其他位置。
	 */
	static final String ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";

	/**
	 * 属性,用于提供要导入的其他位置。
	 */
	static final String IMPORT_PROPERTY = "spring.config.import";
	如果未找到{@link#LOCATION_PROPERTY},则使用默认搜索位置。
	static final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;
	static {
		List<ConfigDataLocation> locations = new ArrayList<>();
		locations.add(ConfigDataLocation.of("optional:classpath:/;optional:classpath:/config/"));
		locations.add(ConfigDataLocation.of("optional:file:./;optional:file:./config/;optional:file:./config/*/"));
		DEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);
	}

#processAndApply

void processAndApply() {
		ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,
				this.loaders);
		registerBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);
		ConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);
		ConfigDataActivationContext activationContext = createActivationContext(
				contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
		contributors = processWithoutProfiles(contributors, importer, activationContext);
		activationContext = withProfiles(contributors, activationContext);
		contributors = processWithProfiles(contributors, importer, activationContext);
		applyToEnvironment(contributors, activationContext, importer.getLoadedLocations(),
				importer.getOptionalLocations());
	}


this.contributors(ConfigDataEnvironment的构造方法里面会赋值成下面这个样子)
	ROOT null null []
    	EXISTING null null []
    	EXISTING null null []
    	EXISTING null null []
    	EXISTING null null []
    	EXISTING null null []
    	EXISTING null null []
    	INITIAL_IMPORT null null []
    	INITIAL_IMPORT null null []

#processInitial

private ConfigDataEnvironmentContributors processInitial(ConfigDataEnvironmentContributors contributors,
			ConfigDataImporter importer) {
		this.logger.trace("Processing initial config data environment contributors without activation context");
		contributors = contributors.withProcessedImports(importer, null);
		registerBootstrapBinder(contributors, null, DENY_INACTIVE_BINDING);
		return contributors;
	}

处理从所有活动贡献者的导入,并返回一个新的{@link configDataEnvironmentContractors}实例。
#withProcessedImports
ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer,
			ConfigDataActivationContext activationContext) {
		ImportPhase importPhase = ImportPhase.get(activationContext);
		this.logger.trace(LogMessage.format("Processing imports for phase %s. %s", importPhase,
				(activationContext != null) ? activationContext : "no activation context"));
		ConfigDataEnvironmentContributors result = this;
		int processed = 0;
		while (true) {
            //第一个contributor是INITIAL_IMPORT null null []
			ConfigDataEnvironmentContributor contributor = getNextToProcess(result, activationContext, importPhase);
			if (contributor == null) {
				this.logger.trace(LogMessage.format("Processed imports for of %d contributors", processed));
				return result;
			}
            //第一个contributor的king是INITIAL_IMPORT
            //第一个contributor的king是INITIAL_IMPORT
            //经过第一二此分别给INITIAL_IMPORT添加了子节点,第三个contributor是
            //UNBOUND_IMPORT optional:classpath:/;optional:classpath:/config/ class path resource [config/application.yml] []

			if (contributor.getKind() == Kind.UNBOUND_IMPORT) {
				Iterable<ConfigurationPropertySource> sources = Collections
						.singleton(contributor.getConfigurationPropertySource());
				PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(
						result, activationContext, true);
				Binder binder = new Binder(sources, placeholdersResolver, null, null, null);
				ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(binder);
				result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
						result.getRoot().withReplacement(contributor, bound));
				continue;
			}
			ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(
					result, contributor, activationContext);
			ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
            //第一次的imports为optional:file:./;optional:file:./config/;optional:file:./config/*/
            //第一次的imports为optional:classpath:/;optional:classpath:/config/
			List<ConfigDataLocation> imports = contributor.getImports();
			this.logger.trace(LogMessage.format("Processing imports %s", imports));
            //判断处理optional:classpath:/;optional:classpath:/config/有相关文件的路径
            //OriginTrackedMapPropertySource {name='Config resource 'class path resource [application.properties]' via location 'optional:classpath:/''}
            //OriginTrackedMapPropertySource {name='Config resource 'class path resource [config/application.yml]' via location 'optional:classpath:/config/''}
			Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext,
					locationResolverContext, loaderContext, imports);
			this.logger.trace(LogMessage.of(() -> getImportedMessage(imported.keySet())));
			ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase,
					asContributors(imported));
            //返回的result给第一个INITIAL_IMPORT添加了空的孩子节点
            //INITIAL_IMPORT null null []
            //    EMPTY_LOCATION optional:file:./;optional:file:./config/;optional:file:./config/*/ null                 //                  [IGNORE_IMPORTS]
            //返回的result给第二个INITIAL_IMPORT添加了空的孩子节点
            //INITIAL_IMPORT null null []
            //    kind为UNBOUND_IMPORT  文件路径为config/application.yml
            //    UNBOUND_IMPORT optional:classpath:/;optional:classpath:/config/ class path resource          							[config/application.yml] []
            //    kind为UNBOUND_IMPORT  文件路径为application.properties
        	//	  UNBOUND_IMPORT optional:classpath:/;optional:classpath:/config/ class path resource 									[application.properties] []
			result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,
					result.getRoot().withReplacement(contributor, contributorAndChildren));
           
			processed++;
		}
	}

#ConfigDataLocationResolverContext

/**
 * 上下文提供给{@link ConfigDataLocationResolver}方法。
 */
public interface ConfigDataLocationResolverContext {

	/**
	 * 提供对活页夹的访问,该活页夹可用于获取以前提供的值。
	 * @return a binder instance
	 */
	Binder getBinder();

	/**
	 *提供对触发解析的父项{@link ConfigDataResource}的访问,如果没有可用的父项,则提供对{@code null}的访问。
	 */
	ConfigDataResource getParent();

	/**
	 *提供对所有{@link EnvironmentPostProcessor EnvironmentPostProcessors}共享的{@link ConfigurableBootstrapContext}的访问。
	 */
	ConfigurableBootstrapContext getBootstrapContext();

}

#Binder

绑定一个或多个{@link ConfigurationPropertySource ConfigurationPropertySources}对象的容器对象。

#resolveAndLoad



//解析并加载给定的位置列表,过滤之前加载的任何位置。

//locations===>optional:file:./;optional:file:./config/;optional:file:./config/*/
Map<ConfigDataResolutionResult, ConfigData> resolveAndLoad(ConfigDataActivationContext activationContext,
			ConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext,
			List<ConfigDataLocation> locations) {
		try {
			Profiles profiles = (activationContext != null) ? activationContext.getProfiles() : null;
			List<ConfigDataResolutionResult> resolved = resolve(locationResolverContext, profiles, locations);
            //ConfigData加载对应文件下的属性
			return load(loaderContext, resolved);
		}
		catch (IOException ex) {
			throw new IllegalStateException("IO error on loading imports from " + locations, ex);
		}
	}

private List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext locationResolverContext,
			Profiles profiles, List<ConfigDataLocation> locations) {
		List<ConfigDataResolutionResult> resolved = new ArrayList<>(locations.size());
		for (ConfigDataLocation location : locations) {
			resolved.addAll(resolve(locationResolverContext, profiles, location));
		}
		return Collections.unmodifiableList(resolved);
	}

private List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext locationResolverContext,
			Profiles profiles, ConfigDataLocation location) {
		try {
			return this.resolvers.resolve(locationResolverContext, location, profiles);
		}
		catch (ConfigDataNotFoundException ex) {
			handle(ex, location, null);
			return Collections.emptyList();
		}
	}

List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location,
			Profiles profiles) {
		if (location == null) {
			return Collections.emptyList();
		}
		for (ConfigDataLocationResolver<?> resolver : getResolvers()) {
			if (resolver.isResolvable(context, location)) {
				return resolve(resolver, context, location, profiles);
			}
		}
		throw new UnsupportedConfigDataLocationException(location);
	}

resolver==>StandardConfigDataLocationResolver
location==>optional:classpath:/;optional:classpath:/config/
private List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolver<?> resolver,
			ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) {
		List<ConfigDataResolutionResult> resolved = resolve(location, false, () -> resolver.resolve(context, location));
		if (profiles == null) {
			return resolved;
		}
		List<ConfigDataResolutionResult> profileSpecific = resolve(location, true,
				() -> resolver.resolveProfileSpecific(context, location, profiles));
		return merge(resolved, profileSpecific);
	}


private List<ConfigDataResolutionResult> resolve(ConfigDataLocation location, boolean profileSpecific,
			Supplier<List<? extends ConfigDataResource>> resolveAction) {
		List<ConfigDataResource> resources = nonNullList(resolveAction.get());
        //
		List<ConfigDataResolutionResult> resolved = new ArrayList<>(resources.size());
		for (ConfigDataResource resource : resources) {
			resolved.add(new ConfigDataResolutionResult(location, resource, profileSpecific));
		}
		return resolved;
	}


@Override
	public List<StandardConfigDataResource> resolve(ConfigDataLocationResolverContext context,
			ConfigDataLocation location) throws ConfigDataNotFoundException {
		return resolve(getReferences(context, location.split()));
	}
 
//configDataLocations:
//    optional:classpath:/
//    optional:classpath:/config/
	private Set<StandardConfigDataReference> getReferences(ConfigDataLocationResolverContext context,
			ConfigDataLocation[] configDataLocations) {
		Set<StandardConfigDataReference> references = new LinkedHashSet<>();
		for (ConfigDataLocation configDataLocation : configDataLocations) {
			references.addAll(getReferences(context, configDataLocation));
		}
		return references;
	}


private Set<StandardConfigDataReference> getReferences(ConfigDataLocationResolverContext context,
			ConfigDataLocation configDataLocation) {
        //得到文件的路径
		String resourceLocation = getResourceLocation(context, configDataLocation);
		try {
            //判断是否是文件夹(判断是否是以/结尾的)
			if (isDirectory(resourceLocation)) {
				return getReferencesForDirectory(configDataLocation, resourceLocation, NO_PROFILE);
			}
			return getReferencesForFile(configDataLocation, resourceLocation, NO_PROFILE);
		}
		catch (RuntimeException ex) {
			throw new IllegalStateException("Unable to load config data from '" + configDataLocation + "'", ex);
		}
	}


private String getResourceLocation(ConfigDataLocationResolverContext context,
			ConfigDataLocation configDataLocation) {
        //prefix:resource
		String resourceLocation = configDataLocation.getNonPrefixedValue(PREFIX);
        //判断是否是决定地址
		boolean isAbsolute = resourceLocation.startsWith("/") || URL_PREFIX.matcher(resourceLocation).matches();
		if (isAbsolute) {
			return resourceLocation;
		}
		ConfigDataResource parent = context.getParent();
		if (parent instanceof StandardConfigDataResource) {
			String parentResourceLocation = ((StandardConfigDataResource) parent).getReference().getResourceLocation();
			String parentDirectory = parentResourceLocation.substring(0, parentResourceLocation.lastIndexOf("/") + 1);
			return parentDirectory + resourceLocation;
		}
		return resourceLocation;
	}


//
  directory====>classpath:/
  profile====>null
  configDataLocation===>optional:classpath:/
private Set<StandardConfigDataReference> getReferencesForDirectory(ConfigDataLocation configDataLocation,
			String directory, String profile) {
		Set<StandardConfigDataReference> references = new LinkedHashSet<>();
        //this.configNames: application
		for (String name : this.configNames) {
			Deque<StandardConfigDataReference> referencesForName = getReferencesForConfigName(name, configDataLocation,
					directory, profile);
			references.addAll(referencesForName);
		}
		return references;
	}


#name===>application
#directory===>classpath:/
#profile===> null
private Deque<StandardConfigDataReference> getReferencesForConfigName(String name,
			ConfigDataLocation configDataLocation, String directory, String profile) {
		Deque<StandardConfigDataReference> references = new ArrayDeque<>();
        //yaml和properties的解析器 
		for (PropertySourceLoader propertySourceLoader : this.propertySourceLoaders) {
            //首先是properties的解析器 propertySourceLoader.getFileExtensions()===>"properties", "xml"
			for (String extension : propertySourceLoader.getFileExtensions()) {
				StandardConfigDataReference reference = new StandardConfigDataReference(configDataLocation, directory,
						directory + name, profile, extension, propertySourceLoader);
				if (!references.contains(reference)) {
					references.addFirst(reference);
				}
			}
		}
		return references;
	}


private List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) {
    	//判断路径是否合法
		if (!this.resourceLoader.isPattern(reference.getResourceLocation())) {
			return resolveNonPattern(reference);
		}
		return 
            resolvePattern(reference);
	}


private List<StandardConfigDataResource> resolveNonPattern(StandardConfigDataReference reference) {
        //resource
    	//		path:application.properties
        //      classloader:类加载器
		Resource resource = this.resourceLoader.getResource(reference.getResourceLocation());
		if (!resource.exists() && reference.isSkippable()) {
			logSkippingResource(reference);
			return Collections.emptyList();
		}
		return Collections.singletonList(createConfigResourceLocation(reference, resource));
	}

#getReferences的最终返回结果

#reference

在这里插入图片描述

#referencesForName

在这里插入图片描述

#getResolvers()的返回值

在这里插入图片描述

#ConfigDataResolutionResult类介绍

class ConfigDataResolutionResult {

    //被解析文件的位置
	private final ConfigDataLocation location;
    //被解析文件的属性key-value
	private final ConfigDataResource resource;

	private final boolean profileSpecific;

	ConfigDataResolutionResult(ConfigDataLocation location, ConfigDataResource resource, boolean profileSpecific) {
		this.location = location;
		this.resource = resource;
		this.profileSpecific = profileSpecific;
	}

	ConfigDataLocation getLocation() {
		return this.location;
	}

	ConfigDataResource getResource() {
		return this.resource;
	}

	boolean isProfileSpecific() {
		return this.profileSpecific;
	}

}

#load

private Map<ConfigDataResolutionResult, ConfigData> load(ConfigDataLoaderContext loaderContext,
			List<ConfigDataResolutionResult> candidates) throws IOException {
		Map<ConfigDataResolutionResult, ConfigData> result = new LinkedHashMap<>();
		//candidates:封装文件路径的集合类
		for (int i = candidates.size() - 1; i >= 0; i--) {
			ConfigDataResolutionResult candidate = candidates.get(i);
			//得到默认默认路径:optional:classpath:/;optional:classpath:/config/
			ConfigDataLocation location = candidate.getLocation();
            //class path resource [application.properties]
			ConfigDataResource resource = candidate.getResource();
			if (resource.isOptional()) {
				this.optionalLocations.add(location);
			}
			if (this.loaded.contains(resource)) {
				this.loadedLocations.add(location);
			}
			else {
				try {
					ConfigData loaded = this.loaders.load(loaderContext, resource);
					if (loaded != null) {
						this.loaded.add(resource);
						this.loadedLocations.add(location);
						result.put(candidate, loaded);
					}
				}
				catch (ConfigDataNotFoundException ex) {
					handle(ex, location, resource);
				}
			}
		}
		return Collections.unmodifiableMap(result);
	}


<R extends ConfigDataResource> ConfigData load(ConfigDataLoaderContext context, R resource) throws IOException {
		ConfigDataLoader<R> loader = getLoader(context, resource);
		this.logger.trace(LogMessage.of(() -> "Loading " + resource + " using loader " + loader.getClass().getName()));
		return loader.load(context, resource);
	}


#真正加载文件属性的方法
@Override
	public ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResource resource)
			throws IOException, ConfigDataNotFoundException {
		if (resource.isEmptyDirectory()) {
			return ConfigData.EMPTY;
		}
		ConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, resource.getResource());
    	//reference包含的属性 
    	//	configDataLocation  optional:classpath:/
        //  resourceLocation   classpath:/application.properties
    	//  directory          classpath:/
        //  profile                    null
        // propertySourceLoader  properties的加载器
 		StandardConfigDataReference reference = resource.getReference();
    	//构架新的Resouce
		Resource originTrackedResource = OriginTrackedResource.of(resource.getResource(),
				Origin.from(reference.getConfigDataLocation()));
    	//name的值 ==>  Config resource 'class path resource [application.properties]' via location             							'optional:classpath:/'
		String name = String.format("Config resource '%s' via location '%s'", resource,
				reference.getConfigDataLocation());
		List<PropertySource<?>> propertySources = reference.getPropertySourceLoader().load(name, originTrackedResource);
		PropertySourceOptions options = (resource.getProfile() != null) ? PROFILE_SPECIFIC : NON_PROFILE_SPECIFIC;
		return new ConfigData(propertySources, options);
	}


name:不在往下追加,读取文件内容
@Override
	public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
		List<Map<String, ?>> properties = loadProperties(resource);
		if (properties.isEmpty()) {
			return Collections.emptyList();
		}
		List<PropertySource<?>> propertySources = new ArrayList<>(properties.size());
		for (int i = 0; i < properties.size(); i++) {
			String documentNumber = (properties.size() != 1) ? " (document #" + i + ")" : "";
			propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
					Collections.unmodifiableMap(properties.get(i)), true));
		}
		return propertySources;
	}


private List<Map<String, ?>> loadProperties(Resource resource) throws IOException {
    	//application.properties
		String filename = resource.getFilename();
		List<Map<String, ?>> result = new ArrayList<>();
		if (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {
			result.add((Map) PropertiesLoaderUtils.loadProperties(resource));
		}
		else {
			List<Document> documents = new OriginTrackedPropertiesLoader(resource).load();
			documents.forEach((document) -> result.add(document.asMap()));
		}
		return result;
	}

经过上述步骤就已经将yml或者properties中的配置信息读取到了contributor中

在这里插入图片描述

SpringAware的调用时间

ApplicationContextAwareProcessor处理

在这里插入图片描述

private void invokeAwareInterfaces(Object bean) {
    	//感知当前的环境在Bean生命周期中的初始化阶段被ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法执行
	    //Environment: 具有判断当前环境和提供properties属性访问的能力
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
    //
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
        //感知资源访问器
	    //在Bean生命周期中的初始化阶段被ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法执行
	   //ResourceLoader: 具有访问本地、classpath、WEB-INF目录下资源的能力

		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
        //感知应用的事件发布器
	   //在Bean生命周期中的初始化阶段被ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法执行
	   //ApplicationEventPublisher: 具有发布事件的能力
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
    	//感知支持国际化消息解析器
	 *Bean生命周期中的初始化阶段被ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法执行
	 * MessageSource: 具有支持国际化的消息解析的能力
	 */
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
      感知Spring应用上下文
	 *Bean生命周期中的初始化阶段被ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法执行
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

initializeBean#invokeAwareMethods(beanName, bean)

if (bean instanceof Aware) {
			//感知Bean实例自身的BeanName,在Bean生命周期中的初始化阶段执行
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            //感知Bean实例自身的ClassLoader,在Bean生命周期中的初始化阶段执行
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            //感知Bean实例自身所在的BeanFactory,在Bean生命周期中的初始化阶段执行
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
      }

使用@MapperScan配置多数据源

@Configuration
@MapperScan(basePackages = "com.xxx", annotationClass = DatasourceRead.class, sqlSessionFactoryRef = DatasourceNewsReadConfig.SQL_SESSION_FACTORY_NAME)
public class DatasourceNewsReadConfig
{
    public static final String SQL_SESSION_FACTORY_NAME = "sessionFactoryNewsRead";
    public static final String TX_MANAGER = "txManagerNewsRead";
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    @Autowired
    private MybatisProperties properties;
 
    @Bean(name = "datasourceNewsRead")
    @ConfigurationProperties(prefix = "spring.datasource.newsread")
    @Primary
    public DataSource datasource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = TX_MANAGER)
    @Primary
    public PlatformTransactionManager txManagerUser() {
        return new DataSourceTransactionManager(datasource());
    }
 
    @Bean(name = DatasourceNewsReadConfig.SQL_SESSION_FACTORY_NAME)
    @Primary
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
 
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(datasource());
        sqlSessionFactoryBean.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        sqlSessionFactoryBean.setMapperLocations(this.properties.getMapperLocations());
        return sqlSessionFactoryBean.getObject();
    }
 
}
   if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
  }



使用@MapperScan配置多数据源

```java
@Configuration
@MapperScan(basePackages = "com.xxx", annotationClass = DatasourceRead.class, sqlSessionFactoryRef = DatasourceNewsReadConfig.SQL_SESSION_FACTORY_NAME)
public class DatasourceNewsReadConfig
{
    public static final String SQL_SESSION_FACTORY_NAME = "sessionFactoryNewsRead";
    public static final String TX_MANAGER = "txManagerNewsRead";
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    @Autowired
    private MybatisProperties properties;
 
    @Bean(name = "datasourceNewsRead")
    @ConfigurationProperties(prefix = "spring.datasource.newsread")
    @Primary
    public DataSource datasource() {
        return DataSourceBuilder.create().build();
    }
 
    @Bean(name = TX_MANAGER)
    @Primary
    public PlatformTransactionManager txManagerUser() {
        return new DataSourceTransactionManager(datasource());
    }
 
    @Bean(name = DatasourceNewsReadConfig.SQL_SESSION_FACTORY_NAME)
    @Primary
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
 
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(datasource());
        sqlSessionFactoryBean.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        sqlSessionFactoryBean.setMapperLocations(this.properties.getMapperLocations());
        return sqlSessionFactoryBean.getObject();
    }
 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring 框架是一个开源的Java应用框架,其核心思想是IoC(控制反转)和AOP(面向切面编程)。Spring 框架的源码非常庞大,涵盖了各个模块和功能的实现,其中核心模块是 Spring Framework。我可以为您提供一些关于 Spring 源码分析的指导: 1. 理解整体结构:首先,您需要了解 Spring 框架的整体结构,从高层次了解各个模块之间的关系,包括核心容器、数据访问、Web、AOP 等模块。 2. 阅读源码:建议从 Spring Framework 的核心模块开始,阅读核心容器的源码。可以选择使用 Eclipse、IntelliJ IDEA 等集成开发环境来浏览源码,这样可以更方便地跳转到相关代码和查看方法的实现。 3. 深入理解 IoC 容器:IoC 是 Spring 框架的核心思想之一。通过阅读源码,深入理解 IoC 容器的实现原理,包括 Bean 的加载、初始化、依赖注入等过程。关注 ApplicationContext 接口及其实现类的源码。 4. 学习 AOP 的实现:AOP 是 Spring 框架另一个重要的特性。了解 AOP 的实现原理,学习关于代理模式、切面、连接点等概念。阅读 Spring AOP 模块的源码,并了解如何使用 AspectJ 注解或 XML 配置来定义切面。 5. 调试和实践:在阅读源码时,可以结合调试功能,跟踪代码的执行流程,观察对象的创建和依赖注入过程。通过实际编写一些简单的 Spring 应用程序,加深对源码的理解。 请注意,由于 Spring 源码庞大且复杂,阅读源码需要有一定的 Java 和框架知识基础,并具备耐心和时间。建议在学习过程中结合官方文档、参考书籍和社区资源,也可以参考一些开源项目中对 Spring 的使用。祝您学习愉快!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值