注意:本文均采用JavaConfig的方式注入,而不是采用XML的方式进行配置。如果需要使用XML的方式注入,本文可以作为一个参考。
1. SpEL介绍
SpEL全称 Spring Expression Language(Spring表达式语言),是一种应用于Spring环境下的一种语言格式。
通常来说,我们往Spring环境中注入值,可以使用properties文件,也可以使用SpEL进行注入,效果是一样的。
2. 环境配置
本文采用的是Maven进行配置,以下是需要用到的pom文件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>s
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
3. Properties配置文件注入
在classpath目录下新建一个properties文件,命名为jdbc.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.userName=root
jdbc.password=xxx
jdbc.url.prefix=jdbc.mysql://localhost:3306/
jdbc.url.suffix=?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
新建一个普通组件(Component)类
@Component
@PropertySource(value = {"classpath:/jdbc.properties"})
public class DataBaseUtils {
@Value("${jdbc.userName}")
private String userName;
@Value("${jdbc.password}")
private String passWord;
@Value("${jdbc.driverClass}")
private String driverClass;
@Value("${jdbc.url.prefix}")
private String urlPrefix;
@Value("${jdbc.url.suffix}")
private String urlSuffix;
private ComboPooledDataSource dataSource;
@Bean
public DataSource getDevDataSource(@Value("${jdbc.password}") String passWord) throws PropertyVetoException {
System.out.println("来自dev环境");
dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(urlPrefix + "java" + urlSuffix);
dataSource.setUser(userName);
dataSource.setPassword(passWord);
dataSource.setDriverClass(driverClass);
return dataSource;
}
}
可以使用@Value
注解进行参数的注入,@PropertySource
注解的作用是定位配置文件。
语法格式:"${配置文件中描述的值}"。
因为可能引入多个配置文件,因此建议给配置文件中的属性进行全路径描述。
3.1 属性注入
@Value("${jdbc.url.prefix}")
private String urlPrefix;
3.2 方法参数注入
public DataSource getDevDataSource(@Value("${jdbc.password}") String passWord){}
3.3 使用EmbeddedValueResolverAware
注入
需要实现EmbeddedValueResolverAware
接口,接着实现setEmbeddedValueResolver
方法,Spring容器会在装载Bean对象之前,往里面注入一个StringValueResolver
对象
@Component
@PropertySource(value = {"classpath:/jdbc.properties"})
public class DataBaseUtils implements EmbeddedValueResolverAware {
private String password;
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.password = resolver.resolveStringValue("${jdbc.password}");
}
}
3.4 使用EnvironmentAware
注入
Spring容器会在装载Bean对象之前,往里面注入一个Environment
对象,通过环境变量,我们可以非常强大的得到想要的结果
@Component
@PropertySource(value = {"classpath:/jdbc.properties"})
public class DataBaseUtils implements EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
Environment
提供了以下四种获取配置文件中值的方式:
/**
* 获得配置文件中定义的值
*/
String getProperty(String key);
/**
* 获得配置文件中定义的值,没有则返回预设的默认值
*/
String getProperty(String key, String defaultValue);
/**
* 获得配置文件中定义的值,可以是一个Class类对象,也就是key可以为对象的全路径描述
*/
<T> T getProperty(String key, Class<T> targetType);
/**
* 获得配置文件中定义的值,可以是一个Class类对象,如果没有那么返回一个预设值
*/
<T> T getProperty(String key, Class<T> targetType, T defaultValue);
4. SpEL注入
语法格式:#{待解析的值}
,请记住,前面是#
不是$
4.1 获得配置文件的值之属性注入
@Value(#{systemProperties['jdbc.driverClass']})
private String driverClass;
4.2 获得配置文件值之方法参数注入
public DataSource getDevDataSource(@Value(#{systemProperties['jdbc.passWord']}) String passWord){
//方法主体省略
}
5. SpEL其他用法
5.1 常规用法
- 获得浮点值:
@Value("#{1.234}")
,注:以后直接简略写成#{1.234}
- 获得科学计数法值:
#{1.234E5}
- 获得String值:
#{"Hello"}
- 获得布尔值:
#{false}
- 获得已装配对象:
#{DataBaseUtils}
- 引用已装配对象的值:
#{DataBaseUtils.password}
- 获得方法的返回值:
#{DataBaseUtils.getDevDataSource()}
- 对返回值进行操作:
#{DataBaseUtils.getDevDataSource().getConnection()}
- 判断返回值是否为空:
#{DataBaseUtils.getDevDataSource()?.getConnection()}
,spring会检测传递的值是否为空,为空则不调用,直接返回null
- 对返回值进行操作:
- 获得Java内置对象:
T{java.lang.Math}
- 获得属性:
T{java.lang.Math}.PI
- 调用方法:
T{java.lang.Math}.random()
- 获得属性:
5.2 高级用法
- 逻辑运算:连接符使用and,or,not
- 复合运算:
#{2 * T{java.lang.Math}.PI * circle.radius}
- 连接运算:
#{DataBaseUtils.urlPrefix + 'java' + DataBaseUtils.urlSuffix}
- 比较运算:
#{DataBaseUtils.userName == root}
或#{DataBaseUtils.userName eq root}
- 三元运算:
#{DataBaseUtils.userName == root ? "ok" : "no"}
- 正则表达式:
#{DataBaseUtils.password matches '[a-zA-Z0-9]{6,12}'}
- 计算集合:
#{songs[1]}
,得到songs里面的第二首歌曲- 得到属性:
#{songs[1].title}
- 得到属性:
- 计算字符串:
#{'This is Hello'[3]}
,得到字符串中第4个字符 - 查询运算符:
#{songs.?[title eq 'hello']}
,得到歌曲中名字等于hello的歌曲- 匹配第一个:
#{songs.^[title eq 'hello']}
- 匹配最后一个:
#{songs.$[title eq 'hello']}
- 匹配第一个:
- 投影运算符:
#{songs.![title]}
,将songs集合中的title取出来,放入对象中