Spring in Action(Spring实战)第三章第五节(3.5 Runtime value injection)讲述运行时注入值,第三章讲述装配bean的一些高级专题,之前的章节一直在讨论用Spring注入bean,实际上,有时候也需要给一些变量注入值。
比如下面的例子其实就是通过构造函数给BlankDisc的title属性注入值,这里用的是硬编码的方式:
1 | //代码清单一,BlankDisc类 |
1 | //代码清单二,使用hardcode注入title和artist |
硬编码常常会引起问题,Spring提供了以下两种方式,在运行时给变量注入值:
- 属性占位符(Property placeholders)
- Spring正则表达式(Spring Expression Language)
从外部注入值
将属性从外部注入到Environment,然后显式地从Environment获取属性值或者使用属性占位符隐式地从Environment获取属性值。
从Environment获取属性值
最简单的方式是定义属性,然后通过Spring的Environment变量获取这些属性。下面的例子演示了如何使用配置文件,从外部注入值,并且装配bean。
1 | //代码清单三,从外部注入title和artist |
与代码清单二使用硬编码不同,代码清单三,从Environment中获取disc.title和disc.artist属性值,在运行时动态地将值注入给BlankDisc的title和artist属性。其中@PropertySource标签指定属性文件的路径。
Environment接口详解
1 | public interface Environment extends PropertyResolver { |
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 | public interface PropertyResolver { |
因为Environment继承自PropertyResolver,所以也包含这些方法。一共有七个名称是或类似getProperty的方法,最前面两个
1 | String getProperty(String key); |
是将字符串原样返回的,带defaultValue的方法指明没有key时,返回defaultValue;
而下面三个:
1 | <T> T getProperty(String key, Class<T> targetType); |
是将字符串解析为指定类型的,其中getPropertyAsClass返回Class
上面这五个方法中,不带defaultValue的两个,当找不到该属性时,返回null。
而剩下的两个方法,方法名包含required字样,在找不到属性时,将抛出IllegalStateException异常:
1 | String getRequiredProperty(String key) throws IllegalStateException; |
此外,containsProperty一目了然,是判断是否包含某属性的。最后,剩下两个用来解析占位符的方法:
1 | String resolvePlaceholders(String text); |
使用属性占位符注入属性值
属性占位符的语法形如${disc.title},比如下面的例子,将使用@Value标签,将disc.title和disc.artist属性分别注入到title和artist。这种方式,实际上也是从Environment获取的,但比从Environment直接获取值更加方便,所以是最经常使用的。
1 | public BlankDisc( |
要使用属性占位符,需要在java配置文件中,加载PropertySourcesPlaceholderConfigurer类型的bean:
1 |
|
使用Spring正则表达式注入属性值
Spring正则表达式可以做到:
- 通过id引入bean
- 访问对象的属性或执行方法
- 对值进行数学、关系或逻辑操作
- 正则表达式匹配
- 操作列表和集合
语法是形如:#{1}。比如#{1}表示数值1,#{T(System).currentTimeMillis()}获取当前时间,#{sgtPeppers.artist}表示sgtPeppers对象的artist属性等。其实,Spring正则表达式的用法和freemarker的模板语言很像。我(笔者)个人觉得,在后端没有必要使用这么复杂的表达式。对于对象级别的数据,从数据库获取好过用表达式注入。而对于函数操作,使用java类库,可读性也比表达式好很多。
实际上,与spring正则表达式相比,最常用的还是上面所说的,用@Value标签指定属性占位符,注入属性值的方式。
这一章的其它笔记参看