Spring的运行时值注入是为了在一些应用场景避免将属性值硬编码在配置类中而提供的解决方案,Spring目前提供了几种方式实现运行时值注入,下面咱们分别来说下java
在Spring中,注入外部属性值的最简单方式就是声明一个外部属性源并经过Spring的Environment检索该属性。示例代码以下:正则表达式
package com.example.demo.config; import com.example.demo.model.UserBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; @Configuration @PropertySource("classpath:app.properties") public class ValueAutoInputConfig { @Autowired private Environment env; @Bean public UserBean userBean(){ return new UserBean(env.getProperty("user.userBean.name"), env.getProperty("user.userBean.password")); } }
对应的属性配置文件app.propertiesspring
user.userBean.name=yanqingzhang user.userBean.password=123456
Environment属性相关方法以下:数组
//获取指定key对应的属性值 String getProperty(String key); //获取指定key对应的属性值,当获取的属性值为空时返回默认值defaultValue String getProperty(String key, String defaultValue); //获取指定key对应的属性值,指定返回的属性值类型为type指定的类型 <T> T getProperty(String key, Class<T> type); //获取指定key对应的属性值,指定返回的属性值类型为type指定的类型,当获取的属性值为null时返回默认值defaultValue <T> T getProperty(String key, Class<T> type, T defaultValue); //获取key对应的属性值,默认返回的String对象,若是未指定属性key则抛出IllegalStateException异常 String getRequiredProperty(String key) throws IllegalStateException; //获取key对应的属性值,并基于type指定返回的属性值类型,若是未指定属性key则抛出IllegalStateException异常 <T> T getRequiredProperty(String var1, Class<T> type) throws IllegalStateException; //判断指定属性key是否存在 boolean containsProperty(String key);
Spring支持将属性定义到外部的属性文件中,而后在Spring Bean须要的使用的时候使用占位符将属性值注入进来,占位符的使用形式为”${}“,咱们下面列举在XML和@Value注解中使用属性占位符app
在使用占位符以前咱们首先必须配置一个PropertySourcesPlaceholderConfigurer类bean,咱们能够采用两种方式配置该Spring Bean一种是在XML配置文件中添加命令空间<context:property-placeholder />,内容以下:dom
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <context:property-placeholder /> </beans>
另外一种则是使用@Bean注解在Java配置类中声明,代码以下:性能
@Configuration @PropertySource("classpath:app.properties") @ComponentScan(basePackageClasses = {UserBean.class}) public class ValueAutoInputConfig { @Autowired private Environment env; @Bean public PropertySourcesPlaceholderConfigurer placeholderConfigurer(){ return new PropertySourcesPlaceholderConfigurer(); } }
1)在XML配置文件中使用占位符ui
<bean id="userBean" class="com.jiayun.spring.learn.model.UserBean"> <property name="name" value="${user.userBean.name}" /> <property name="password" value="${user.userBean.password}" /> </bean>
2)在@Value注解中使用属性占位符this
@Component public class UserBean { @Value("${user.userBean.name}") private String name; @Value("${user.userBean.password}") private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
解析外部属性可以将值的处理推迟到运行时,可是它只能根据属性名称获取来自Spring Environment和外部属性源的属性配置,下面讲述的Spring表达式语言(SpEL)提供更增强大的功能编码
Spring表达式语言(SpEL)可以以一种很是简介且强大的方式将运行时外部值装配到到bean属性和构造器参数中,它主要有如下几种使用方式:
1)表示字面值
@Component public class UserBean { @Value("#{'yanqingzhang'}") private String name; @Value("#{123456}") private String password; ...... }
2)引用Bean、属性和方法
引用Bean
@Service public class UserBeanQuery { @Value("#{userBean}") private UserBean userBean; ...... }
引用Bean属性
@Service public class UserBeanQuery { @Value("#{userBean.name}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
引用方法
@Service public class UserBeanQuery { @Value("#{userBean.getName().toUpperCase()}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
为了不userBean.getName()返回的String对象为null还能够这样写防止NullPointException,采用如下方式写执行到getName方法返回null对象时表达式直接返回null再也不执行后面的转大写方法toUpperCase
@Service public class UserBeanQuery { @Value("#{userBean.getName()?.toUpperCase()}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
3)在表达式中使用类型
若是须要在表达式中访问类做用域的方法和常量必须得依赖T()这个关键的运算符,例如要在SpEL表达式中使用Java的Math类能够写成T(java.io.Math),T()关键运算符的做用是可让咱们能够访问目标类内部的静态成员变量和静态成员方法,固然咱们也能够将T()运算符结果的Class对象和普通Bean同样装配到Bean属性中
@Service public class UserBeanQuery { @Value("#{T(java.lang.Math).random()*20}") private int age; }
4)SpEL运算符
SpEL提供了许多运算符,几乎支持全部的算术、比较、逻辑、条件、正则运算,如下运算符均可以应用于SpEL表达式
运算符类型 | 运算符 |
算术运算 | +、-、*、/、%、^ |
比较运算符 | <、>、==、<=、>=、lt、gt、eq、le、ge |
逻辑运算符 | and、or、not、| |
条件运算符 | 三元运算( exp ? value1 : value2)、Evis运算符(exp ?: value) |
正则表达式 | matches |
这里讲解下Evis运算符的使用,例如这样一个Evis运算符表达式exp ?: value 假如exp是null那么表达式的计算结果就是value。以下给出在@Value注解上使用示例:
@Service public class UserBeanQuery { @Value("#{userBean.getName() ?: 'defaultName'}") private String userName; public String getUserName(){ System.out.println(userName); return userName; } }
5 )使用正则表达式
@Service public class UserBeanQuery { @Value("#{userBean.email matches '[a-zA-Z0-9_]+@[a-zA-Z_]+\\.com'}") private boolean isTrueEmail; public Boolean isTrueEmail(){ return isTrueEmail; } }
注意UserBean的类中必须实现email属性的get/set方法
6 - 计算集合
SpEL支持基于索引下标获取集合和数组的元素,在此基础上还提供了查询运算符 ” .?[] “,他会用来对集合或数组进行过滤获得集合或者数组的一个子集过滤条件放在中括号[]以内,SpEL还支持其余两个运算符” .^[ ] “和” .$[ ]“分别用于在集合中查询匹配中括号内过滤条件的第一项和最后一项元素,最后SpEL表达式还支持投影运算符” .![] “他会从集合中每一个元素中选择指定属性放到另一个集合上,这个属性在中括号[]中指定,如下是在@Value注解中的使用示例