Spring5 强大飘逸的表达式语言
一、探讨Environment的使用
1、Spring属性解析器标准接口介绍
public interface PropertyResolver {//检查是否包含该属性,包含返回true,否则返回falseboolean 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);//根据属性标识获取该属性对应的值,必须定义,如果没有获取到属性会抛出异常、没有指定返回类型String getRequiredProperty(String key) throws IllegalStateException;//根据属性标识获取该属性对应的值,必须定义,如果没有获取到属性会抛出异常(IllegalStateException)、指定返回类型<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;//解析占位符,非必须定义String resolvePlaceholders(String text);//解析占位符,必须定义,否则抛出异常String resolveRequiredPlaceholders(String text) throws IllegalArgumentException}
2、Spring Environment接口介绍
public interface Environment extends PropertyResolver {//获得激活的Profile数组String[] getActiveProfiles();//获得默认的Profile数组String[] getDefaultProfiles();//支持给定的profileboolean acceptsProfiles(String... profiles);boolean acceptsProfiles(Profiles profiles);}
3、Spring Environment的使用
创建配置文件app.properties
app.id=icyptapp.name=冰点科技
创建配置类JavaConfig.java
@Configuration@PropertySource(value = , encoding = )public class JavaConfig {private Environment environment;public AppService appService() {return new AppService(environment.getRequiredProperty("app.id"), environment.getProperty("app.name"));}}
创建AppService.java
public class AppService {private String appId;private String appName;public AppService(String appId, String appName) {this.appId = appId;this.appName = appName;}public String toString() {return "AppService{" +"appId='" + appId + '\'' +", appName='" + appName + '\'' +'}';}}
创建测试类TestAppService.java
public class TestAppService {public static final Logger logger = LoggerFactory.getLogger(TestAppService.class);public static AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(JavaConfig.class);public void TestToString() {AppService appService = acac.getBean("appService", AppService.class);logger.info(appService.toString());}}
运行测试结果:
16:17:17,917 DEBUG main env.PropertySourcesPropertyResolver:115 - Found key 'app.id' in PropertySource 'class path resource [app.properties]' with value of type String16:17:17,917 DEBUG main env.PropertySourcesPropertyResolver:115 - Found key 'app.name' in PropertySource 'class path resource [app.properties]' with value of type String16:17:17,953 INFO main service.TestAppService:23 - AppService{appId='icypt', appName='冰点科技'}
总结一下:
以上这个测试我先定义了一个配置文件,在这个配置文件中定义了两对属性,当AppService实例化时通过Environment实例获取配置文件属性并通过构造注入到AppService实例之中完成实例化,最后打印了APPService的toString方法,由日志可以看出,完全符合我们想要的结果,至于Environment的其他方法就不一一演示了,大家化几分钟时间去测试一下,比较简单。
二、属性占位符的使用
Spring支持将属性值定义到外部的配置文件中,并使用占位符的方式将其插入到SpringBean中,所谓的占位符就是“${...}”。
1、JavaConfig中使用:
修改JavaConfig.java
@Beanpublic AppService appService(String appId, String appName) {return new AppService(appId, appName);}
通过@Value,我们就可以获取到app.properties中对应的属性值。
2、XMLConfig中使用:
创建UserService.java
public class UserService {private String userName;private String password;private String appId;private String appName;public UserService(String userName, String password, String appId, String appName) {this.userName = userName;this.password = password;this.appId = appId;this.appName = appName;}public String toString() {return "UserService{" +"userName='" + userName + '\'' +", password='" + password + '\'' +", appId='" + appId + '\'' +", appName='" + appName + '\'' +'}';}}
创建配置文件:
<?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:c="http://www.springframework.org/schema/c"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--<context:property-placeholder/>--><context:component-scan base-package="com.icypt"/><bean id="userService" class="com.icypt.learn.service.UserService"c:userName="dg"c:appId="${app.id}"c:appName="${app.name}"c:password="123"/></beans>
创建测试类TestUserService.java:
public class TestUserService {public static final Logger logger = LoggerFactory.getLogger(TestUserService.class);public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("application.xml");public void TestToString() {UserService userService = cpxac.getBean("userService", UserService.class);logger.info(userService.toString());}}
运行结果:
17:11:07,285 DEBUG main env.PropertySourcesPropertyResolver:115 - Found key 'app.name' in PropertySource 'class path resource [app.properties]' with value of type String17:11:07,286 DEBUG main env.PropertySourcesPropertyResolver:115 - Found key 'app.name' in PropertySource 'environmentProperties' with value of type String17:11:07,326 INFO main service.TestUserService:24 - UserService{userName='dg', password='123', appId='icypt', appName='冰点科技'}
在Xml中使用占位符时一定要注意:
要么在Xml中配置<context:property-placeholder/>,要么在JavaConfig中配置:
@Beanpublic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {return new PropertySourcesPlaceholderConfigurer();}
否则,Spring无法识别占位符,将以字符串的形式注入到属性当中,类似“${app.id}”。
三、Spring常用表达式的使用
Spring3引入了Spring表达式语言(Spring Expression Language, SpEL),它能够以一种强大和简洁的方式将值装配到Bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。
下面将常见的表达式在XML中使用做一演示,来激发你写出更加风骚的表达式:
1、演示前的准备工作
创建UserTags.java
public class UserTag {private String tagName;private String title;public String getTagName() {return tagName;}public void setTagName(String tagName) {this.tagName = tagName;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}}
修改UserService.java
private List<UserTag> tagList;
2、演示常用SpEL表达式
修改配置文件:
<?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:c="http://www.springframework.org/schema/c"xmlns:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd"><!--<context:property-placeholder/>--><context:component-scan base-package="com.icypt"/><bean id="userService" class="com.icypt.learn.service.UserService"c:userName="dg"c:appId="${app.id}"c:appName="${app.name}"c:password="123"p:tagList-ref="lists"/><!--标签集合--><util:list id="lists"><bean class="com.icypt.learn.service.UserTag"p:tagName="java" p:title="java develop"/><bean class="com.icypt.learn.service.UserTag"p:tagName="java" p:title="java test"/><bean class="com.icypt.learn.service.UserTag"p:tagName="spring" p:title="spring develop"/><bean class="com.icypt.learn.service.UserTag"p:tagName="spring" p:title="spring test"/><bean class="com.icypt.learn.service.UserTag"p:tagName="mybatis" p:title="mybatis develop"/></util:list><!-- 常见表达式使用 --><bean id="expressionService" class="com.icypt.learn.service.ExpressionService"><!-- 当前时间毫秒数 --><property name="currentTimeMilis" value="#{ T(System).currentTimeMillis()}"/><!-- 获取对象属性 --><property name="appId" value="#{userService.getAppId()}"/><!-- 获取系统属性,Spring在容器加载的时候会把System.getProperties()获取的值默认放在systemProperties中 --><property name="javaVersion" value="#{systemProperties['java.version']}"/><!--转换科学计数法所得到的值--><property name="salary" value="#{9.2E3}"/><!--根据BeanID引入Bean--><property name="userService" value="#{userService}"/><!--注入对象为空判断--><property name="appName" value="#{appService.getAppName()?.substring(1)}"/><!--指定返回结果类型--><property name="randomNum" value="#{T(java.lang.Math).random()}"/><!--基本运算符的使用--><property name="baseOperator" value="#{(100 + 1) * 2}"/><!--三目运算符使用以及验证空--><property name="trinocular" value="#{userService.getPassword()?:'is blank'}"/><!--正则表达式使用--><property name="regex" value="#{userService.getUserName().matches('[a-z]')}"/><!--数组使用--><property name="arrayFirst" value="#{userService.getTagList()[0].getTagName()}"/><!--查询运算符,获得第一个值, 从tagList中找到第一个tagName等于java的tag,然后获取tagName--><property name="queryFirst" value="#{userService.getTagList().^[tagName eq 'java'].getTitle()}"/><!--查询运算符,获得最后一个值,从tagList中找到最后一个tagName等于java的tag,然后获取tagName--><property name="queryLast" value="#{userService.getTagList().$[tagName eq 'spring'].getTitle()}"/><!--投影运算符,从tagList中重组所有tagName的集合--><property name="projection" value="#{userService.getTagList().![tagName]}"/></bean></beans>
3、创建测试类
public class TestExpressionService {public static final Logger logger = LoggerFactory.getLogger(TestExpressionService.class);public static ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("application.xml");public void TestToString() {ExpressionService expressionService = cpxac.getBean("expressionService", ExpressionService.class);logger.info("当前时间毫秒数:" + expressionService.getCurrentTimeMilis().toString());logger.info("获取对象属性,appId:" + expressionService.getAppId());logger.info("获取系统属性,java.version:" + expressionService.getJavaVersion());logger.info("转换科学计数法所得到的值,salary:" + expressionService.getSalary());logger.info("根据BeanID引入Bean:" + expressionService.getUserService().toString());logger.info("注入对象为空判断,appName:" + expressionService.getAppName());logger.info("指定返回结果类型,randomNum:" + expressionService.getRandomNum());logger.info("基本运算符的使用,baseOperator:" + expressionService.getBaseOperator());logger.info("三目运算符使用以及验证空,trinocular:" + expressionService.getTrinocular());logger.info("正则表达式使用,regex:" + expressionService.getRegex());logger.info("数组使用,arrayFirst:" + expressionService.getArrayFirst());logger.info("查询运算符,获得第一个值,queryFirst:" + expressionService.getQueryFirst());logger.info("查询运算符,获得最后一个值,queryLast:" + expressionService.getQueryLast());logger.info("投影运算符,projection:" + expressionService.getProjection());}}
运行结果:
21:11:20,121 INFO main service.TestExpressionService:24 - 当前时间毫秒数:155671628000321:11:20,121 INFO main service.TestExpressionService:25 - 获取对象属性,appId:icypt21:11:20,121 INFO main service.TestExpressionService:26 - 获取系统属性,java.version:1.8.0_13121:11:20,123 INFO main service.TestExpressionService:27 - 转换科学计数法所得到的值,salary:9200.021:11:20,124 INFO main service.TestExpressionService:28 - 根据BeanID引入Bean,userServiceID:UserService{userName='dg', password='123', appId='icypt', appName='冰点科技'}21:11:20,124 INFO main service.TestExpressionService:29 - 注入对象为空判断,appName:点科技21:11:20,124 INFO main service.TestExpressionService:30 - 指定返回结果类型,randomNum:021:11:20,125 INFO main service.TestExpressionService:31 - 基本运算符的使用,baseOperator:20221:11:20,125 INFO main service.TestExpressionService:32 - 三目运算符使用以及验证空,trinocular:12321:11:20,125 INFO main service.TestExpressionService:33 - 正则表达式使用,regex:false21:11:20,125 INFO main service.TestExpressionService:34 - 数组使用,arrayFirst:java21:11:20,125 INFO main service.TestExpressionService:35 - 查询运算符,获得第一个值,queryFirst:java develop21:11:20,126 INFO main service.TestExpressionService:36 - 查询运算符,获得最后一个值,queryLast:spring test21:11:20,126 INFO main service.TestExpressionService:37 - 投影运算符,projection:[java, java, spring, spring, mybatis]
由运行结果可以得出已经达到了表达式所需要表达的预期效果,到此,Spring表达式就探讨完了,大家可以根据上面这些例子,脑洞大开,写出更加飘逸的表达式来测试。那么我们有关Spring的第一大特性(依赖注入(IOC)与控制反转(DI))基本都探讨完了,下次我们正式进入面向切面编程,也就是所谓的AOP。
关注我↓↓↓
您的关注是对我最大的鼓励!
