Spring in Acton 4读书笔记之在运行时注入值

Spring in Action(Spring实战)第三章第五节(3.5 Runtime value injection)讲述运行时注入值,第三章讲述装配bean的一些高级专题,之前的章节一直在讨论用Spring注入bean,实际上,有时候也需要给一些变量注入值。

比如下面的例子其实就是通过构造函数给BlankDisc的title属性注入值,这里用的是硬编码的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//代码清单一,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;
}

}
1
2
3
4
5
6
7
//代码清单二,使用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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//代码清单三,从外部注入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接口详解

1
2
3
4
5
6
7
8
public interface Environment extends PropertyResolver {

String[] getActiveProfiles();

String[] getDefaultProfiles();

boolean acceptsProfiles(String... profiles);
}

Environment继承自PropertyResolver,并另外添加了几个和Profiles相关的方法,Profiles是用来标记运行环境是开发环境还是生产环境的,更多内容请看我前几天写的这篇读书笔记(Spring in Acton 4 读书笔记之根据开发环境装配 bean)[http://tantanit.com/springinacton4-du-shu-bi-ji-zhi-gen-ju-kai-fa-huan-jing-zhuang-pei-bean/]

PropertyResolver顾名思义,是用来解析属性的,所以大部分方法名都包含Property字样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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的方法,最前面两个

1
2
3
String getProperty(String key);

String getProperty(String key, String defaultValue);

是将字符串原样返回的,带defaultValue的方法指明没有key时,返回defaultValue;

而下面三个:

1
2
3
4
5
6
<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异常:

1
2
3
String getRequiredProperty(String key) throws IllegalStateException;

<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;

此外,containsProperty一目了然,是判断是否包含某属性的。最后,剩下两个用来解析占位符的方法:

1
2
3
String resolvePlaceholders(String text);

String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;

使用属性占位符注入属性值

属性占位符的语法形如${disc.title},比如下面的例子,将使用@Value标签,将disc.title和disc.artist属性分别注入到title和artist。这种方式,实际上也是从Environment获取的,但比从Environment直接获取值更加方便,所以是最经常使用的。

1
2
3
4
5
6
public BlankDisc(
@Value("${disc.title}") String title,
@Value("${disc.artist}") String artist) {
this.title = title;
this.artist = artist;
}

要使用属性占位符,需要在java配置文件中,加载PropertySourcesPlaceholderConfigurer类型的bean:

1
2
3
4
@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标签指定属性占位符,注入属性值的方式。

这一章的其它笔记参看

© 2022 谈谈IT All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero