Spring in Action(Spring实战)第三章第五节(3.5 Runtime value injection)讲述运行时注入值,第三章讲述装配bean的一些高级专题,之前的章节一直在讨论用Spring注入bean,实际上,有时候也需要给一些变量注入值。
比如下面的例子其实就是通过构造函数给BlankDisc的title属性注入值,这里用的是硬编码的方式:
//代码清单一,BlankDisc类
public class BlankDisc {
private final String title;
private final String artist;
public BlankDisc(String title, String artist) {
this.title = title;
this.artist = artist;
}
public String getTitle() {
return title;
}
public String getArtist() {
return artist;
}
}
//代码清单二,使用hardcode注入title和artist
@Bean
public CompactDisc sgtPeppers() {
return new BlankDisc(
"Sgt. Pepper's Lonely Hearts Club Band",
"The Beatles");
}
硬编码常常会引起问题,Spring提供了以下两种方式,在运行时给变量注入值:
- 属性占位符(Property placeholders)
- Spring正则表达式(Spring Expression Language)
从外部注入值
将属性从外部注入到Environment,然后显式地从Environment获取属性值或者使用属性占位符隐式地从Environment获取属性值。
从Environment获取属性值
最简单的方式是定义属性,然后通过Spring的Environment变量获取这些属性。下面的例子演示了如何使用配置文件,从外部注入值,并且装配bean。
//代码清单三,从外部注入title和artist
@Configuration
@PropertySource("classpath:/com/soundsystem/app.properties")
public class EnvironmentConfig {
@Autowired
Environment env;
@Bean
public BlankDisc blankDisc() {
return new BlankDisc(
env.getProperty("disc.title"),
env.getProperty("disc.artist"));
}
}
与代码清单二使用硬编码不同,代码清单三,从Environment中获取disc.title和disc.artist属性值,在运行时动态地将值注入给BlankDisc的title和artist属性。其中@PropertySource标签指定属性文件的路径。
Environment接口详解
public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
boolean acceptsProfiles(String... profiles);
}
Environment继承自PropertyResolver,并另外添加了几个和Profiles相关的方法,Profiles是用来标记运行环境是开发环境还是生产环境的,更多内容请看我前几天写的这篇读书笔记(Spring in Acton 4 读书笔记之根据开发环境装配 bean)[tantanit.com/springinact…]
PropertyResolver顾名思义,是用来解析属性的,所以大部分方法名都包含Property字样。
public interface PropertyResolver {
boolean containsProperty(String key);
String getProperty(String key);
String getProperty(String key, String defaultValue);
<T> T getProperty(String key, Class<T> targetType);
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
<T> Class<T> getPropertyAsClass(String key, Class<T> targetType);
String getRequiredProperty(String key) throws IllegalStateException;
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
String resolvePlaceholders(String text);
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}
因为Environment继承自PropertyResolver,所以也包含这些方法。一共有七个名称是或类似getProperty的方法,最前面两个
String getProperty(String key);
String getProperty(String key, String defaultValue);
是将字符串原样返回的,带defaultValue的方法指明没有key时,返回defaultValue;
而下面三个:
<T> T getProperty(String key, Class<T> targetType);
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
<T> Class<T> getPropertyAsClass(String key, Class<T> targetType);
是将字符串解析为指定类型的,其中getPropertyAsClass返回Class类型。
上面这五个方法中,不带defaultValue的两个,当找不到该属性时,返回null。
而剩下的两个方法,方法名包含required字样,在找不到属性时,将抛出IllegalStateException异常:
String getRequiredProperty(String key) throws IllegalStateException;
<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;
此外,containsProperty一目了然,是判断是否包含某属性的。最后,剩下两个用来解析占位符的方法:
String resolvePlaceholders(String text);
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
使用属性占位符注入属性值
属性占位符的语法形如${disc.title},比如下面的例子,将使用@Value标签,将disc.title和disc.artist属性分别注入到title和artist。这种方式,实际上也是从Environment获取的,但比从Environment直接获取值更加方便,所以是最经常使用的。
public BlankDisc(
@Value("${disc.title}") String title,
@Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}
要使用属性占位符,需要在java配置文件中,加载PropertySourcesPlaceholderConfigurer类型的bean:
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
使用Spring正则表达式注入属性值
Spring正则表达式可以做到:
- 通过id引入bean
- 访问对象的属性或执行方法
- 对值进行数学、关系或逻辑操作
- 正则表达式匹配
- 操作列表和集合
语法是形如:#{1}。比如#{1}表示数值1,#{T(System).currentTimeMillis()}获取当前时间,#{sgtPeppers.artist}表示sgtPeppers对象的artist属性等。其实,Spring正则表达式的用法和freemarker的模板语言很像。我(笔者)个人觉得,在后端没有必要使用这么复杂的表达式。对于对象级别的数据,从数据库获取好过用表达式注入。而对于函数操作,使用java类库,可读性也比表达式好很多。
实际上,与spring正则表达式相比,最常用的还是上面所说的,用@Value标签指定属性占位符,注入属性值的方式。
这一章的其它笔记参看
- Spring in Acton 4 读书笔记之根据开发环境装配 bean
- Spring in Action 读书笔记之根据条件创建 bean
- Spring in Action 4 读书笔记之解决自动装配 bean 的二义性问题* Spring in Action 4 读书笔记之如何定义 bean 的使用范围
欢迎搜索“谈谈IT”或扫描下方二维码关注微信公众号,第一时间获取最新文章(^_^)