上一节讲了Spring高级装配的一些要点,主要是将一个bean的引用注入到另外一个bean的属性或构造器参数中。但是,我们有时候需要将一个值注入到bean的属性或者构造器参数中,而这个值是在运行时产生的,这一节主要讲bean装配中经常遇到的运行时值注入问题。
Spring提供了两种在运行时求值的方式:
在Spring中,处理外部值最简单的方式就是声明属性源并通过将Spring的Environment来检索属性。在基于Java的配置中,可以通过@PropertySource注解声明属性源,例如:
package com.example.config;
import com.example.chr1s.BlankDisc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
@Configuration
@PropertySource("classpath:/com/example/chr1s/app.properties") //声明属性源
public class ExpressiveConfig {
@Autowired
Environment env;
@Bean
public BlankDisc disc() {
return new BlankDisc(env.getProperty("disc.title"),
env.getProperty("disc.artist"));
}
}
通过@PropertySource注解声明的配置文件会加载到Spring的Environment中。
Spring的Environment中有四个重载的getProperty()方法:
String getProperty(String key)
String getProperty(String key, String defaultValue)
T getProperty(String key, Class type)
T getProperty(Sgtring key, Class type, T defaultValue)
前两个是通过String类型的键值对实现,后两个不会将所有的值视为String类型,也就是说值可以是任意类型。如果某个属性的值不能为空,可以使用getRequiredProperty()方法,这个方法与getProperty()方法基本一样,只是当key为空的时候会抛出一个IllegalStateException异常。
如果想检查某个属性是否存在的话,可以调用Environment的containsProperty()方法:
boolean isPropertyExist = env.containsProperty("key");
如果想将属性解析为类的话,可以调用getPropertyAsClass()方法:
Class cdClass = env.getPropertyAsClass("key", CompactDisc.class);
Environment提供的一些额外的方法:
String[] getActiveProfiles():返回激活profile名称的数组
String[] getDefaultProfiles():返回默认profile名称的数组
boolean acceptsProfiles(String… profiles):如果environment支持给定的profile的话,返回true;反之,false
用environment能解决很多问题,属性占位符也能很好地解决上述问题。
Spring中,占位符的形式为“${…}”,可以在XML中按照如下的方式解析BlankDisc构造器的参数:
"sgtPeppers" class="com.example.chr1s.BlankDisc"
c:_title="${disc.title}"
c:_artist="${disc.artist}" />
也可以在Java配置文件中使用属性占位符,通过@Value注解来实现:
public BlankDisc(
@Value("${disc.title}") String title,
@Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}
为了使用占位符,必须配置一个PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bean。推荐使用后者,因为它能够基于Spring Environment及其属性源来解析占位符。可以按照如下的方法配置一个相应的bean:
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
在基于XML的配置中,Spring context命名空间的
元素将生成一个PropertySourcesPlaceholderConfigurer bean.
Spring表达式语言相比于占位符提供了一种更加通用的方式在运行时计算所要注入的值。
SpEL具有以下特性:
SpEL还能用于依赖注入以外的其它地方。例如,Spring Security支持使用SpEL表达式定义安全规则(支持正则表达式匹配???),在Spring MVC应用中还可以使用SpEL引用模型数据。
SpEL表达式放在“#{…}”中
如可以通过#{sgtPeppers.artist}
得到artist的属性(这个属性是private的,怎么获取???)
systemProperties对象可以引用系统属性,和env很像。
#{systemProperties['disc.artist']}
在XML配置中,可以将SpEL表达式传入
或
的value属性中。
SpEL能够通过ID引用其他的bean,如前面所述的sgtPeppers。
T()运算符是SpEL相当有用的一个运算符。T()运算符的结果是一个Class对象,T(java.lang.Math)表示java.lang.Math对象。T()运算符的真正价值在于它能够访问目标类型的静态方法和常量。
SpEL还有很多运算符,可以参考其它资料进行了解。