目录
一、背景
通常我们讨论依赖注入时,指的都是将一个 bean 引用注入到另一个 bean 的属性或构造器中,它通常是指对象与对象之间的关联。除此之外,bean 的装配还可以将一个值注入到 bean 的属性或构造器中。但是值注入经常会造成硬编码,如下代码所示:
@Bean
public People getPeople() {
return new Boy("oysq", "boy");
}
与此类似,XML 风格的注入也存在此类硬编码的问题,如:
<bean id="people"
class="aa.bb.People"
c:_name="oysq"
c:_sex="boy" />
所以,我们希望这些值能在运行时再确定,而不是直接编写到代码中。具体有两种方法:
- 属性占位符,用法:${ ... }
- Spring表达式语言(SpEL),用法:#{ ... }
二、用法介绍
1.属性占位符
属性占位符的使用是将值放于配置文件中,并通过声明属性源的方式,使得 Spring 的 Environment 能检索到这些属性,最后通过代码的方式或属性占位符进行注入。
例如,现在我们创建一个配置文件 boy.properties ,内容如下:
boy.name=oysq
boy.age=26
boy.phone=123456789
通过 @PropertySource 注解声明属性源,将其加载到 Spring 的 Environment 中,再通过 Environment 取出注入。
@Configuration
@PropertyEource("classpath:/com/sys/boy.properties")
public class MyConfig {
@Autowired
Environment env;
@Bean
public People getPeople() {
return new Boy(
env.getProperty("boy.name"),
env.getProperty("boy.age")
);
}
}
其中,Environment 除了能获取属性值外,还有很多用法,比如获取 profile 来判断激活状态等等。
如果是自动扫描的的方式,我们在组件处通过 @Value 注解来注入,并需要配置一个 PropertyPlaceholderConfigurer 的 bean 或 PropertySourcesPlaceholderConfigurer 的 bean,从 spring 3.1 开始,推荐使用 PropertySourcesPlaceholderConfigurer,因为它能够基于 Spring Environment 及其属性源来解析占位符。代码如下:
@Component
public class Boy {
private String name;
private String age;
public Boy(
@Value("${boy.name}") String name,
@Value("${boy.age}") String age) {
this.name = name;
this.age = age;
}
}
@Bean
public PropertySourcesPlaceholderConfigurer getPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
而在 xml 中我们使用属性占位符,并通过 <context:property-placeholder /> 来生成 PropertySourcesPlaceholderConfigurer 的 bean,如下:
<bean id="people"
class="aa.bb.People"
c:_name="${boy.name}"
c:_sex="${boy.age}" />
<context:property-placeholder />
2.Spring表达式语言(SpEL)
SpEL 表达式有很多的特性,除了依赖注入,还能用在很多其它的地方。于属性占位符最直接的区别就是它 放在 #{ ... } 之中。
它的特性包括:
- 使用 bean 的 ID 来引用 bean
- 调用方法和访问对象的属性
- 对值进行算数、关系和逻辑运算
- 正则表达式匹配
- 集合操作
这边只简单举例用法:
@Component
public class Boy {
private String name;
private String age;
public Boy(
@Value("#{systemProperty['boy.name']}") String name,
@Value("#{systemProperty['boy.age']}") String age) {
this.name = name;
this.age = age;
}
}
写在最后:虽然 SpEL 表达式很智能,但是建议不要写太复杂,因为毕竟是一个字符串,不好做测试。
(原创不易,转载请注明出处!!)