spring表达式语言 Spring表达式语言

初次遇见@Value注解的时候 , 总以为它的功能非常生硬 , 只能注入硬编码的字面量值 。后来随着学习的深入 , 渐渐发现@Value注解也能注入属性文件的值 , 非常好用 。让人格外惊喜的是 , @Value注解并未止步于此 , 还提供了通过Spring表达式语言(Spring Expression Language, SpEL)注入更加丰富的值的支持 。比如 , com.dream包定义了这样的类:
1 public class MusicWorld {2public static final String DREAM = "Dream";3 }则可这样把SpEL表达式的运算结果注入Bean中:
1 @Component 2 public class Music { 3private String musicName = null; 45@Value("#{T(com.dream.MusicWorld).DREAM + ' work'}") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10// 省略getter方法11 }可以看到musicName属性带有@Value注解 , 其值是括在 #{} 里的SpEL表达式 T(com.dream.MusicWorld).DREAM + ' work'  。这样 , Spring容器瞧见@Value注解之后就能解析SpEL表达式 , 把静态常量MusicWord.DREAM_MUSIC与字符串 work 连接之后得到字符串 Dream work 注入musicName属性里了 。
非常明显 , Spring表达式语言能够使用表达式描述值的注入 , 告诉Spring容器在运行时解析表达式之后把解析出来的结果注入Bean中 。SpEL表达式必须括在 #{} 里 , 既可调用类的静态成员 , Bean的实例成员;也可使用各种运算符进行值的运算 。功能非常强大 , 语法非常简洁 , 用法非常方便 , 大大丰富了值的注入 。现在 , 让我们一起瞧瞧SpEL表达式支持的功能 。
SpEL表达式与字面量值
这是最简单的一种SpEL表达式 。只要把硬编码的数字 , 布尔值 , 字符串等字面量值括在 #{} 里 , 就能通过SpEL表达式注入字面量值了 。其中 , 字符串需要括在两个单引号 ' 里 。如果需要注入的字符串本身就有单引号 , 可用两个单引号 '' 表示 。以下示例就注入了字符串 One's dream :
1 @Component 2 public class Music { 3private String musicName = null; 45@Value("#{'One''s dream'}") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10// 省略getter方法11 }SpEL表达式与集合
SpEL表达式支持集合的注入 。如果集合的类型是Array , List或Set , 可把集合的值使用逗号隔开之后括在 {} 里 。如下所示:
1 @Component 2 public class Music { 3private String[] musicNameArray = null; 4private List<String> musicNameList = null; 5private Set<String> musicNameSet = null; 67@Value("#{{'One', 'Two', 'Three'}}") 8public void setMusicNameArray(String[] musicNameArray) { 9this.musicNameArray = musicNameArray;10}11 12@Value("#{{'One', 'Two', 'Three'}}")13public void setMusicNameList(List<String> musicNameList) {14this.musicNameList = musicNameList;15}16 17@Value("#{{'One', 'Two', 'Three'}}")18public void setMusicNameSet(Set<String> musicNameSet) {19this.musicNameSet = musicNameSet;20}21 22// 省略getter方法23 }如果集合的类型是Map , 能以 键: 值 表示一对键值 , 而后把多对键值使用逗号隔开之后括在 {} 里 。如下所示:
1 @Component 2 public class Music { 3private Map<String, String> musicNameMap = null; 45@Value("#{{OneKey: 'One', TwoKey: 'Two', ThreeKey: 'Three'}}") 6public void setMusicNameMap(Map<String, String> musicNameMap) { 7this.musicNameMap = musicNameMap; 8} 9 10// 省略getter方法11 }访问Bean的属性
SpEL表达式支持以 Bean的ID.Bean的属性名 这样的方式访问Spring容器里的Bean的属性 。假如com.dream包定义了这样的组件:
1 @Component("music") 2 public class Music { 3private String musicName = null; 45@Value("Dream") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10// 省略getter方法11 }则可这样访问ID为music的Bean的musicName属性 , 把它的值注入player中:
1 @Component("player") 2 public class Player { 3private String playingMusicName = null; 45@Value("#{music.musicName}") 6public void setPlayingMusicName(String playingMusicName) { 7this.playingMusicName = playingMusicName; 8} 9 10// 省略getter方法11 }访问Array , List , Set的值
SpEL表达式支持通过中括号 [] 括起索引访问Array , List , Set的值 。假如com.dream包定义了这样的组件: 
1 @Component("music") 2 public class Music { 3private String[] musicNameArray = null; 4private List<String> musicNameList = null; 5private Set<String> musicNameSet = null; 67@Value("#{{'One', 'Two', 'Three'}}") 8public void setMusicNameArray(String[] musicNameArray) { 9this.musicNameArray = musicNameArray;10}11 12@Value("#{{'One', 'Two', 'Three'}}")13public void setMusicNameList(List<String> musicNameList) {14this.musicNameList = musicNameList;15}16 17@Value("#{{'One', 'Two', 'Three'}}")18public void setMusicNameSet(Set<String> musicNameSet) {19this.musicNameSet = musicNameSet;20}21 22// 省略getter方法23 }则可这样指定索引取出Array , List , Set的值 , 把它们注入player中: 
1 @Component("player") 2 public class Player { 3private String playingMusicName_1 = null; 4private String playingMusicName_2 = null; 5private String playingMusicName_3 = null; 67@Value("#{music.musicNameArray[0]}") 8public void setPlayingMusicName_1(String musicName) { 9this.playingMusicName_1 = musicName;10}11 12@Value("#{music.musicNameList[0]}")13public void setPlayingMusicName_2(String musicName) {14this.playingMusicName_2 = musicName;15}16 17@Value("#{music.musicNameSet[0]}")18public void setPlayingMusicName_3(String musicName) {19this.playingMusicName_3 = musicName;20}21 22// 省略getter方法23 }访问Map的值
SpEL表达式支持通过中刮号 [] 括起Map的键访问Map的值 。假如com.dream包定义了这样的组件:
1 @Component("music") 2 public class Music { 3private Map<String, String> musicNameMap = null; 45@Value("#{{OneKey: 'One', TwoKey: 'Two', ThreeKey: 'Three'}}") 6public void setMusicNameMap(Map<String, String> musicNameMap) { 7this.musicNameMap = musicNameMap; 8} 9 10// 省略getter方法11 }则可这样指定Map的键取出Map的值 , 把它注入player中:
1 @Component("player") 2 public class Player { 3private String playingMusicName = null; 45@Value("#{music.musicNameMap['OneKey']}") 6public void setPlayingMusicName(String playingMusicName) { 7this.playingMusicName = playingMusicName; 8} 9 10// 省略getter方法11 }调用Bean的方法
SpEL表达式支持通过 Bean的ID.Bean的方法 这样的方式调用Spring容器里的Bean的方法 。假如com.dream包定义了这样的组件:
1 @Component("music") 2 public class Music { 3private String musicName = null; 45@Value("Dream") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10public String appendMusicName(String appendValue) {11return this.musicName + appendValue;12}13 14// 省略getter方法15 }则可这样调用ID为music的Bean的appendMusicName方法 , 把它的返回值注入player中:
1 @Component("player") 2 public class Player { 3private String playingMusicName = null; 45@Value("#{music.appendMusicName(' work')}") 6public void setPlayingMusicName(String playingMusicName) { 7this.playingMusicName = playingMusicName; 8} 9 10// 省略getter方法11 }T()运算符
SpEL表达式提供了T()运算符用于获取类的Class对象 。只要把全限定类名指给T()运算符 , T()运算符即能获取指定类的Class对象 。因此 , 假如com.dream包定义了这样的类:
1 public class MusicWorld {2public static final String DREAM = "Dream";3 }则可这样通过SpEL表达式获取MusicWorld的Class对象 , 把它注入music中:
1 @Component("music") 2 public class Music { 3private Class musicWorldClass = null; 45@Value("#{T(com.dream.MusicWorld)}") 6public void setMusicWorldClass(Class musicWorldClass) { 7this.musicWorldClass = musicWorldClass; 8} 9 10// 省略getter方法11 }【spring表达式语言 Spring表达式语言】一种常用的用法是使用T()运算符获取类的Class对象之后访问类的静态成员 。如下所示:
1 @Component("music") 2 public class Music { 3private String musicName = null; 45@Value("#{T(com.dream.MusicWorld).DREAM}") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10// 省略getter方法11 }matches运算符
SpEL表达式支持通过matches运算符 , 以 字符串 matches 正则表达式 这样的方式判断某个字符串是否匹配某个正则表达式:如果匹配 , 则返回TRUE;否则返回FALSE 。因此 , 假如com.dream包定义了这样的组件:
1 @Component("music") 2 public class Music { 3private String musicName = null; 45@Value("Dream") 6public void setMusicName(String musicName) { 7this.musicName = musicName; 8} 9 10// 省略getter方法11 }则可这样在SpEL表达式里使用matches运算符 , 看看music的musicName属性的值是不是只有字母 , 并把运算结果注入player中:
1 @Component("player") 2 public class Player { 3private boolean isMusicValid = false; 45@Value("#{music.musicName matches '^[a-zA-Z]+$'}") 6public void setIsMusicValid(boolean isMusicValid) { 7this.isMusicValid = isMusicValid; 8} 9 10// 省略getter方法11 }new运算符
SpEL表达式支持通过new运算符 , 以 new 带有全限定类名的构造函数 这样的方式创建类的实例 。假如com.dream包定义了这样的类: 
1 public class Music {2private String musicName = null;3 4public Music(String musicName) {5this.musicName = musicName;6}7 }则可这样在SpEL表达式里使用new运算符创建Music类的实例 , 把实例注入player中:
1 @Component("player") 2 public class Player { 3private Music playingMusic = null; 45@Value("#{new com.dream.Music('Dream')}") 6public void setMusic(Music playingMusic) { 7this.playingMusic = playingMusic; 8} 9 10// 省略getter方法11 }关系运行符
SpEL表达式提供了这些用于进行关系运算的关系运算符:
1.小于:< (也可使用文本lt)
2.大于:> (也可使用文本gt)
3.小于等于:<= (也可使用文本le)
4.大于等于:>= (也可使用文本ge)
5.等于:== (也可使用文本eq)
6.不等于:!= (也可使用文本ne)
这些关系运算符的用法与Java的关系运算符是一样 , 大家一瞧便知 , 不再详叙 。
逻辑运算符
SpEL表达式提供了这些用于进行逻辑运算的逻辑运算符:
1.与:and
2.或:or
3.非:not
这些逻辑运算符的用法与Java的逻辑运算符是一样 , 大家一瞧便知 , 不再详叙 。
算数运算符
SpEL表达式提供了这些用于进行算数运算的算数运算符:
1.数字的相加或字符串的相连:+
2.减:-
3.乘:*
4.除:/
5.取模:%
6.乘方:^
这些算术运算符的用法与Java的算术运算符是一样 , 大家一瞧便知 , 不再详叙 。
?:运算符
SpEL表达式提供的?:运算符具有两种用法:一种是作为三元运算符(Ternary Operator)用于If-Then-Else的条件运算;一种是作为Elvis运算符用于简化三元运算符关于null值的用法 。
?:运算符用作三元运算符时 , 它的用法和Java的?:运算符是一样的 。如下所示:
1 #{music.musicName != null ? music.musicName: 'There is not any music.'}这条SpEL表达式会先检查 music.musicName 的值是否不等于null:如果不等于null , 则返回 music.musicName 的值;否则返回字符串 There is not any music. 
另外 , 这条SpEL表达式还能使用Elvis运算符这样简化:
1 #{music.musicName ?: 'There is not any music.'}Elvis运算符会先检查 music.musicName 的值是否不等于null:如果不等于null , 则直接返回自己 , 也就是返回
 music.musicName 的值;否则返回 ?: 后面的值 , 也就是返回字符串 There is not any music. 
?.运算符
SpEL表达式提供了?.运算符用于安全地访问Bean的属性 , 调用Bean的方法 。按照以往的写法 , 我们总是这样访问Bean的属性 , 调用Bean的方法:
1 #{music.musicName}2 #{music.appendMusicName(' work')}毫无疑问 , 如果music等于null , 程序定会抛出异常 。为了避免这样的错误 , 我们可用?.运算符修改如下:
1 #{music?.musicName}2 #{music?.appendMusicName(' work')}我们把 . 换成了?.运算符 。这样 , 当music等于null时 , 这条SpEL表达式只会返回null , 不会抛出异常;当music不等于null时 , 这条SpEL表达式才会访问Bean的属性 , 调用Bean的方法 。
至此 , 关于SpEL表达式的介绍该告一段落了 。当然 , XML配置文件也是支持SpEL表达式的 , 而且用法与@Value注解一模一样 。大家一看下面的示例就知道了:
1 <bean id="music_1" class="com.dream.Music">2<property name="musicName" 3value="https://tazarkount.com/read/#{T(com.dream.MusicWorld).DREAM +' work'}" />4 </bean>5 <bean id="music_2" class="com.dream.Music">6<constructor-arg type="java.lang.String" 7value="https://tazarkount.com/read/#{T(com.dream.MusicWorld).DREAM +' work'}" />8 </bean>下章 , 我们将会开始介绍混合配置 。欢迎大家继续阅读 , 谢谢大家!
返回目录    下载代码