【spring-boot】SpringApplication学习——prepareContext()方法详解

写在前面

在SpringApplication的run()方法启动spring应用的过程中,有三个非常重要的方法,与IOC容器的初始化有关,分别是:

  1. createApplicationContext()
  2. prepareContext();
  3. refreshContext();

这里主要记录关于prepareContext()方法有关的学习笔记。

主要的参数列表
参数类型参数简要说明
ConfigurableApplicationContext contextcreateApplicationContext()方法的返回值,代表应用上下文
ConfigurableEnvironment environment系统的环境变量信息的接口类
SpringApplicationRunListeners listenersSpringApplicationRunListener的集合类
ApplicationArguments applicationArguments应用参数
Banner printedBanner打印的Banner信息

ConfigurableEnvironment概述

AbstractEnvironment是实现ConfigurableEnvironment的抽象类,StandardEnvironment继承了AbstractEnvironment,因此StandardEnvironment是ConfigurableEnvironment 的一个实现类。在spring的官方文档中有这样一段话:

When an Environment is being used by an ApplicationContext, it is important that any such PropertySource manipulations be performed before the context’s refresh() method is called. This ensures that all property sources are available during the container bootstrap process, including use by property placeholder configurers.

大概意思就是说如果在ApplicationContext中使用到了系统环境变量类Environment(也可以是继承种的下游类或者接口),那么在调用上下文context的refresh()方法之前,那些关于PropertySource的操作应该全部操作完成,这一点非常的重要,因为这样可以确保在整个容器启动的过程中,所有的property sources都是可用的。
关于这一点,在下面ConfigurableEnvironment的实例代码中也得到了验证。

下面的代码示例表示是在环境变量中添加一个新的property sources。

@ComponentScan("com.xlrainy")
@EnableAutoConfiguration
@Configuration
@MapperScan("com.xlrainy.domain")
public class MyApplication {

    public static void main(String[] args){

        SpringApplication application = new SpringApplication(MyApplication.class);

        /**
         * ConfigurableEnvironment示例代码部分
         */
        ConfigurableEnvironment environment = new StandardEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();
        Map<String, Object> myMap = new HashMap<>();
        myMap.put("xlcheng", "zhangsy");
        propertySources.addFirst(new MapPropertySource("MY_P", myMap));
        System.err.println(propertySources.get("MY_P"));

        application.run(args);
    }
}

在environment中添加了一个名为"MY_P"的属性,name为"xlcheng",value为"zhangsy",在run()方法之前调用,启动spring应用,在终端的输出
在这里插入图片描述
可以看到在Banner输出之前对这些Environment 属性进行了配置,也就是在refresh()方法被调用之前完成了环境属性的操作。

ConfigurableEnvironment源码
  • SpringApplication的run()方法中的ConfigurableEnvironment
private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (this.webApplicationType == WebApplicationType.NONE) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

在代码的第5行、第6行创建一个ConfigurableEnvironment 的实现类对象,并且对其进行配置。根据应用的不同类型(webApplicationType),可以得到的实现类有:

  1. StandardServletEnvironment
  2. StandardEnvironment

ConfigurableEnvironment、StandardEnvironment、StandardServletEnvironment这几个类之间的继承关系如下图所示:
继承结构图

  • SpringApplication对ConfigurableEnvironment的配置
protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}
protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		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));
			}
		}
	}

可以看出上面对环境变量的配置基本都是围绕着MutablePropertySources这个对象来的。其实MutablePropertySources对象内部维护了PropertySource<?>类型的List,代码如下:

public class MutablePropertySources implements PropertySources {
	private final Log logger;
	private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
	
	public MutablePropertySources() {
		this.logger = LogFactory.getLog(getClass());
	}
	
	public MutablePropertySources(PropertySources propertySources) {
		this();
		for (PropertySource<?> propertySource : propertySources) {
			addLast(propertySource);
		}
	}
}

而PropertySource对象是真正需要配置属性对象。他的源码如下:

public abstract class PropertySource<T> {
	protected final Log logger = LogFactory.getLog(getClass());
	protected final String name;
	protected final T source;

name一般表示配置的环境变量名称,T类型的source是属性的列表,一般T可以是一个Map。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值