Elim的博客

用来记录一些原创性的总结


Elim

20 @PropertySource

在之前介绍<context:property-placeholder/>时提到过其默认会使用PropertySourcesPlaceholderConfigurer来进行对应的属性替换,其底层有使用PropertySource。@PropertySource是用来注册一个PropertySource的。PropertySource是用来表示一个name/value属性配对的资源的,可以简单的把它理解为我们熟悉的Properties。

Environment可以持有一系列的PropertySource,然后在从中获取属性时,其会依次从对应的PropertySource中寻找,当然也包括系统属性和环境变量。一个Environment中默认会包含两个PropertySource,分别对应于系统属性和环境变量。即默认情况下在只有系统属性和环境变量对应的两个ProperySource时,如果我们从Environment中获取某属性,将先从系统属性中取,没取到再从环境变量中获取。所以,如下示例我们直接从Environment中获取属性“user.dir”的值,这里取的就是系统属性“user.dir”的值。

	@Test
	public void testPropertySource() {
		ConfigurableApplicationContext context = new GenericApplicationContext();
		ConfigurableEnvironment env = context.getEnvironment();
		String userDir = env.getProperty("user.dir");
		System.out.println(userDir);
		context.close();
	}

我们也可以往Environment中添加PropertySource对象,之后添加的PropertySource对象就可以用来获取对应的属性。如下示例中我们往Environment中添加了一个基于类路径下的init.properties文件的ResourcePropertySource,且是加在所有的PropertySource之前,由于在从Environment中获取属性时,将优先从前面的PropertySource中获取。那么如果我们在init.properies文件中定义了一个user.dir属性,则下面示例中获取到的user.dir就将是我们在init.properties文件中指定的那个。

	@Test
	public void testPropertySource() throws IOException {
		ConfigurableApplicationContext context = new GenericApplicationContext();
		//获取Environment对象
		ConfigurableEnvironment env = context.getEnvironment();
		//获取Environment的PropertySources
		MutablePropertySources propertySources = env.getPropertySources();
		//new一个基于Resource的PropertySource
		ResourcePropertySource rps = new ResourcePropertySource(new ClassPathResource("init.properties"));
		//给当前Environment对象env添加一个PropertySource对象
		propertySources.addFirst(rps);
		String userDir = env.getProperty("user.dir");
		System.out.println(userDir);
		context.close();
	}

接下来我们来介绍一下@PropertySource。@PropertySource需要和@Configuration一起使用。其可以让我们非常方便的把外部资源定义封装成一个PropertySource对象添加到对应的Environment中。如下示例中我们通过在使用@Configuration进行标注的配置类上通过@PropertySource标注引入了一个类路径下的init.properties文件作为一个PropertySource添加到了当前的Environment中(当指定的资源未指定前缀时默认就会当做ClassPathResource处理)。之后我们在创建bean时就可以使用Environment对象来获取其中拥有的PropertySource中定义的属性对应的属性值,如下述示例中我们在创建hello时就从Environment中获取了属性“hello.name”的值。

@Configuration
@PropertySource("init.properties")
public class SpringConfig {

	@Autowired
	private Environment env;
	
	@Bean
	public Hello hello() {
		String helloName = env.getProperty("hello.name");
		Hello hello = new Hello(helloName);
		return hello;
	}
	
}

如果需要同时将多个外部文件作为PropertySource添加到对应的Environment中,则我们可以通过@PropertySource的value属性指定多个资源,其对应于一个数组。如下示例中我们就同时将类路径下的init.properties和init2.properties文件作为PropertySource添加到当前的Environment中。

@Configuration
@PropertySource({"init.properties", "init2.properties"})
public class SpringConfig {
	
}

我们也可以通过@PropertySources注解来定义多个@PropertySource,以添加多个PropertySource到Environment中。

@Configuration
@PropertySources({@PropertySource("init.properties"), @PropertySource("init2.properties")})
public class SpringConfig {

}

默认情况下我们通过@PropertySource指定的资源是必须存在的,否则Spring将抛出异常,当然我们也可以通过@PropertySource的ignoreResourceNotFound属性来指定是否忽略资源未找到的情况,默认为false,表示不忽略。如下示例中我们就通过ignoreResourceNotFound指定了忽略init.properties文件不存在的情况。

@Configuration
@PropertySource(value="init.properties", ignoreResourceNotFound=true)
public class SpringConfig {

}

(注:本文是基于Spring4.1.0所写)