Spring學習(二十三)Spring表示式語言介紹
- Spring表示式語言的入門介紹
- Spring表示式語言的操作範圍
- Spring表示式語言的運算子
- Spring表示式語言的集合操作
1.基本概述 Spring表示式語言全稱為“Spring Expression Language”,縮寫為“SpEL”,他能在執行時構建複雜表示式、存取物件屬性、物件方法呼叫等等,並且能與Spring功能完美整合。表示式語言給靜態Java語言增加了動態的功能,表示式語言是單獨的模組,他只依賴與核心的模組,不依賴與其他模組,能夠單獨的使用。表示式語言通常是以最簡單的形式完成最複雜的工作來減少我們的工作量,Spring語言主要支援如下的表示式。
- 基本表示式
- 類相關表示式
- 集合相關表示式
- 其他表示式
public class SpelTest { public static void main(String[] args){ //建立解析器 ExpressionParser parser=new SpelExpressionParser(); //解析表示式 Expression expression= parser.parseExpression("('Hello'+'World').concat(#end)"); //構造上下文 EvaluationContext context=new StandardEvaluationContext(); //為end引數值來賦值 context.setVariable("end","!"); //列印expression表示式的值 System.out.println(expression.getValue(context)); } }
3.工作原理 在介紹Spring表示式語言工作原理之前,先介紹一下一些基本概念:
- 表示式:表示式語言的核心,即“幹什麼”
- 解析器:用於將字串表示式解析為表示式物件,即“誰來幹”
- 上下文:表示式語言執行的環境,該環境可能定義變數,可能定義自定義函式,也可以提供型別轉換等等,即“在哪裡幹”
- 根物件即活動上下文物件:根物件是預設的活動上下文物件,活動上下文物件表示了當前操作物件。即“對誰幹”
- ExpressionParser介面:表示解析器
- EvaluationContext介面:表示上下文環境
- Expression介面:表示的是表示式物件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="world" class="java.lang.String">
<constructor-arg value="#{' World!'}"/>
</bean>
<!--方式一-->
<bean id="hello1" class="java.lang.String">
<constructor-arg value="#{'Hello '}#{world}"/>
</bean>
<!--方式二
注意:Spring語言不支援巢狀,即在一個#之內又有一個#
<constructor-arg value="#{'Hello '#{world}}"/>-->
<bean id="hello2" class="java.lang.String">
<constructor-arg value="#{'Hello '+world}"/>
</bean>
<!--方式三-->
<bean id="hello3" class="java.lang.String">
<constructor-arg value="#{'Hello '[email protected]}"/>
</bean>
</beans>
可以看到,我們使用了三種使用Spring表示式語言的方法來在配置檔案中配置bean的引數。 接下來我們建立一個測試類來測試下各個bean的值
public class XmlExpression {
public static void main(String[] args){
ApplicationContext ctx=
new FileSystemXmlApplicationContext("src/conf/conf-spel.xml");
String hello1=ctx.getBean("hello1",String.class);
String hello2=ctx.getBean("hello2",String.class);
String hello3=ctx.getBean("hello3",String.class);
System.out.println(hello1);
System.out.println(hello2);
System.out.println(hello3);
}
}
另外一種配置Spring表示式語言的方法便是註解方式。 註解風格的配置: 基於註解風格的SpEL配置也非常簡單,使用@Value註解來指定SpEL表示式,該註解可以放到欄位、方法以及方法引數上。 我們使用示例來演示以下,首先修改配置檔案
<!--開啟註解支援-->
<context:annotation-config/>
<bean id="hellobean1" class="cn.lovepi.chapter05.spel.AnnoExpression"/>
<bean id="hellobean2" class="cn.lovepi.chapter05.spel.AnnoExpression">
<property name="value" value="haha"/>
</bean>
聲明瞭兩個bean,其中一個使用屬性注入的方式注入了特定的引數。由於使用了註解,所以得在配置檔案中開啟註解支援。 接下來編寫對應的java程式碼
public class AnnoExpression {
@Value("#{'Hello '+world}")
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public static void main(String[] args){
ApplicationContext ctx=
new FileSystemXmlApplicationContext("src/conf/conf-spel.xml");
AnnoExpression hellobean1=ctx.getBean("hellobean1",AnnoExpression.class);
AnnoExpression hellobean2=ctx.getBean("hellobean2",AnnoExpression.class);
System.out.println(hellobean1.getValue());
System.out.println(hellobean2.getValue());
}
}
通過結果可以看出:使用引數注入方式注入的值會覆蓋Spring表示式所編寫的值 二.Spring表示式語言的操作範圍
SpEL表示式的首要目標是通過計算獲得某個值,在計算這個值的過程中,會使用到其他的值並會對這些值進行操作,值的操作範圍如下:
- 字面值:最簡單的一種值,即基本型別的表示式。包含的型別是字串、數字型別(int、lang、float、double、boolean、null)字串使用單引號分割,使用反斜槓字元轉義。
- Bean以及Bean的屬性或方法:通過id來引入其他的bean或者bean的屬性或方法
- 類的方法和常量:在SpEL中是由T運算子呼叫類的方法和常量
public class SpelLiteral {
private int count;
private String message;
private float frequency;
private float capacity;
private String name1;
private String name2;
private boolean enabled;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public float getFrequency() {
return frequency;
}
public void setFrequency(float frequency) {
this.frequency = frequency;
}
public float getCapacity() {
return capacity;
}
public void setCapacity(float capacity) {
this.capacity = capacity;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String getName2() {
return name2;
}
public void setName2(String name2) {
this.name2 = name2;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
可以看到該Bean有很多基本資料型別以及String型別的屬性,接下來我們一一在配置檔案中為這些屬性使用Spring表示式語言賦值<bean id="spelliteral" class="cn.lovepi.chapter05.spel.SpelLiteral">
<property name="count" value="#{5}"/>
<property name="message" value="The value is #{5}"/>
<property name="frequency" value="#{89.7}"/>
<property name="capacity" value="#{1e4}"/>
<property name="name1" value="#{'wang'}"/>
<property name="name2" value='#{"wang"}'/>
<property name="enabled" value="#{false}"/>
</bean>
在這裡我們使用了property屬性注入的方式來為Bean的屬性注入引數,可以看到使用Spring表示式語言可以表示多種型別的值。
接下來我們建立個測試類來測試下是否將值正確的注入到Bean當中去。
public class SpelMain {
public static void main(String[] args){
testSpelLiteral();
}
private static void testSpelLiteral(){
ApplicationContext ctx=
new FileSystemXmlApplicationContext("src/conf/conf-spel.xml");
SpelLiteral literal=ctx.getBean("spelliteral",SpelLiteral.class);
System.out.println("count= "+literal.getCount());
System.out.println("message= "+literal.getMessage());
System.out.println("frequency= "+literal.getFrequency());
System.out.println("capacity= "+literal.getCapacity());
System.out.println("name1= "+literal.getName1());
System.out.println("name2= "+literal.getName2());
System.out.println("enabled= "+literal.isEnabled());
}
}
輸出結果為:
count= 5
message= The value is 5
frequency= 89.7
capacity= 10000.0
name1= wang
name2= wang
enabled= false
SpEL表示式所能做到的另外一個事情便是通過id來引用其他Bean。包括Bean本身,Bean的屬性以及Bean的方法。
SpEL引用Bean本身
<property name="bean2" value="#{bean1}"/>
這句話等價與<property name="bean2" ref="bean1"/>
可以看到使用SpEL表示式並不如直接使用ref標籤來引用其他Bean來的方便,但SpEL在下面的使用體驗可就非常棒了。
SpEL引用Bean的屬性<bean id="bean2" class="cn.lovepi.***">
<property name="name" value="#{bean1.name}"/>
</bean>
以上的程式碼等價於
Bean2 bean2=new Bean2();
bean2.setName(bean1.getName());
可以看到使用Spring表示式語言可以更方便的獲取Bean的屬性 SpEL引用Bean的方法 獲取bean1的name值將其賦值給bean2的屬性中
<property name="name" value="#{bean1.getName()}/>
還可以將獲取到的name值轉換為大寫<property name="name" value="#{bean1.getName().toUpperCase()}/>
但是這種情況只能在getName方法不返回空值的情況下,假如getName返回空值的話則會丟擲空指標異常。
在SpEL中,為了避免空指標異常可以使用如下的方法:<property name="name" value="#{bean1?.getName().toUpperCase()}/>
在這裡我們使用使用“?.”運算子來代替“.”運算子,這樣可以確保在左邊不為空的情況下才執行右邊的方法,否則將不執行。
接下來我們使用示例來演示下,首先我們建立一個Java Bean,其中包括兩個float的屬性
public class SpelClass {
private float pi;
private float randomNumber;
public float getPi() {
return pi;
}
public void setPi(float pi) {
this.pi = pi;
}
public float getRandomNumber() {
return randomNumber;
}
public void setRandomNumber(float randomNumber) {
this.randomNumber = randomNumber;
}
}
為其編寫配置檔案<bean id="spelClass" class="cn.lovepi.chapter05.spel.SpelClass">
<property name="pi" value="#{T(java.lang.Math).PI}"/>
<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>
</bean>
可以看到我們使用SpEL使用了Math類的屬性PI和方法random()。
讓我們測試一下
private static void testSpelClass(){
ApplicationContext ctx=
new FileSystemXmlApplicationContext("src/conf/conf-spel.xml");
SpelClass spelClass=ctx.getBean("spelClass",SpelClass.class);
System.out.println("PI="+spelClass.getPi());
System.out.println("randomNumber="+spelClass.getRandomNumber());
}
可以看到最後結果為:
PI=3.1415927
randomNumber=0.541514
三.Spring表示式語言的運算子上面我們介紹了Spring表示式語言所能操作的值的範圍,接下來我們來學習下如何來操作這些值,即SpEL的運算子。
運算子型別 | 運算子示例 |
數值運算 | +、-、*、/、%、^(乘方運算) |
比較運算 | <(lt)、>(gt)、==(eg)、<=(le)、>=(ge) |
邏輯運算 | and、or、not、| |
條件運算 | ?:(ternary)、?:(Elvis) |
正則表示式 | matches |
public class SpelCounter {
private float total;
private float count;
public float getTotal() {
return total;
}
public void setTotal(float total) {
this.total = total;
}
public float getCount() {
return count;
}
public void setCount(float count) {
this.count = count;
}
}
接下來建立一個運算演示Beanpublic class SpelMath {
private float ajustedAcount;
private float circumFference;
private float average;
private float remainder;
private float area;
private String fullName;
public float getAjustedAcount() {
return ajustedAcount;
}
public void setAjustedAcount(float ajustedAcount) {
this.ajustedAcount = ajustedAcount;
}
public float getCircumFference() {
return circumFference;
}
public void setCircumFference(float circumFference) {
this.circumFference = circumFference;
}
public float getAverage() {
return average;
}
public void setAverage(float average) {
this.average = average;
}
public float getRemainder() {
return remainder;
}
public void setRemainder(float remainder) {
this.remainder = remainder;
}
public float getArea() {
return area;
}
public void setArea(float area) {
this.area = area;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
}
在配置檔案中使用SpEL表示式語言運算子來對相應的資料進行運算賦值操作
<bean id="spelCounter" class="cn.lovepi.chapter05.spel.SpelCounter">
<property name="count" value="#{10}"/>
<property name="total" value="#{100}"/>
</bean>
<bean id="spelMath" class="cn.lovepi.chapter05.spel.SpelMath">
<!--加法運算子-->
<property name="ajustedAcount" value="#{spelCounter.total+53}"/>
<!--乘法運算子-->
<property name="circumFference" value="#{2*T(java.lang.Math).PI*spelCounter.total}"/>
<!--除法運算子-->
<property name="average" value="#{spelCounter.total/spelCounter.count}"/>
<!--取餘運算子-->
<property name="remainder" value="#{spelCounter.total%spelCounter.count}"/>
<!--乘方運算子-->
<property name="area" value="#{T(java.lang.Math).PI * spelCounter.total^2}"/>
<!--字串拼接-->
<property name="fullName" value="#{'icarus'+' '+'wang'}"/>
</bean>
接下來在程式入口出測試程式執行結果private static void testSpelMath(){
ApplicationContext ctx=
new FileSystemXmlApplicationContext("src/conf/conf-spel.xml");
SpelMath math=ctx.getBean("spelMath",SpelMath.class);
System.out.println("AjustedAcount= "+math.getAjustedAcount());
System.out.println("CircumFference= "+math.getCircumFference());
System.out.println("Average= "+math.getAverage());
System.out.println("Area= "+math.getArea());
System.out.println("Remainder= "+math.getRemainder());
System.out.println("FullName= "+math.getFullName());
}
可以看到程式的執行結果為:
AjustedAcount= 153.0
CircumFference= 628.31854
Average= 10.0
Area= 31415.926
Remainder= 0.0
FullName= icarus wang
2.比較運算
SpEL表示式同樣提供Java所支援的比較運算子,但為了適應XML的配置規則,SpEL提供了文字型比較運算子
3.邏輯運算子 邏輯運算子用於對兩個比較表示式進行求值,或者對某些布林型別的值進行非運算,下表列出了SpEL當中的所有邏輯運算子
4.條件運算 當某個條件為true時,SpEL的表示式的求值結果是某個值;如果該條件為false時,它到的求值結果是另一個值時,可以使用SpEL的三元運算子。(?:): SpEL的三元運算子的使用和Java相同,其主要作用是判斷一個值是否為null,並對其進行處理,如下所示:
<property name="name" value="#{person.name!=null ? person.name : 'icarus'}"/>
但上面的的語句重複使用了兩次person.name屬性,SpEL為我們提供了一種更簡便的方式:<property name="name" value="#{person.name!=null ?: 'icarus'}"/>
這個語句的效果和上面的是相同的。
5.正則表示式
當處理文字時,檢查文字是否匹配某種模式有時是非常有用的。SpEL通過matches運算子支援表示式中的模式匹配。如果匹配則返回true,不匹配則返回false。
假如我們想要對一個郵件地址的字串進行判斷,那麼我們則可以按照如下配置:<property name="validEmail" value="#{admin.email matches '[0-9A-Za-z_%.*+-][email protected][0-9A-Za-z.-]+\\.com'}"/>
四.Spring表示式語言的集合操作 SpEL可以引用集合中的某個成員,就像在Java裡操作一樣,同樣具有基於屬性值來過濾集合成員的能力。SpEl對集合的操作主要包括以下幾種:
- 訪問集合成員
- 查詢集合成員
- 投影集合
public class SpelCity{
private String name;
private String state;
private int population;
}
接下來我們建立一個集合,集合中的元素是SpelCity<util:list id="cities">
<bean class="cn.lovepi.***.SpelCity">
<p:name="Chicago" p:state="IL" p:population="2853114">
<bean class="cn.lovepi.***.SpelCity">
<p:name="LasCryces" p:state="NM" p:population="91865">
</util:list>
2.查詢集合成員
接下來我們演示利用SpEL來查詢集合成員
如果我們想從cities集合當中查詢人口多餘十萬的城市,
那麼一種實現方式是將所有的city Bean都裝配到Bean的屬性當中,然後在該Bean中增加過濾不符合條件的城市。
在SpEL表示式語言當中使用查詢運算子“.?[]”即可實現以上功能。如下所示:
<property name="bigCities" value="#{cities.?[population gt 100000]}"/>
查詢運算子會建立一個新的集合,新的集合當中只存放符合中括號內的值。
SpEL同樣提供了兩種其他的查詢運算子
- .^[]:查詢符合條件的第一個元素
- .$[]:查詢符合條件的最後一個元素
<property name="cityName1" value="#{cities.![name]}}"/>
投影不侷限與投影單一的屬性,如下所示:
將cities集合中的名稱和簡稱都投影出來
<property name="cityName2" value="#{cities.![name+','+state]}}"/>
當然還可以對集合進行查詢和投影的雙重運算:
將大城市的名稱和簡稱都投影出來
<property name="cityName3" value="#{cities.?[population gt 100000].![name+','+state]}}"/>
總結: 雖然SpEL表示式語言非常強大,但是SpEL表示式語言只是一個字串,並沒有id之類的編譯支援,所以並不建議深入學習SpEL表示式,只需瞭解知道即可。
相關推薦
Spring學習(二十三)Spring表示式語言介紹
Spring表示式語言(Spring Expression Language)簡稱:SpEL 課程概要: Spring表示式語言的入門介紹Spring表示式語言的操作範圍Spring表示式語言的運算子
Spring 學習(二十三)——宣告式事務
事務簡介 •事務管理是企業級應用程式開發中必不可少的技術, 用來確保資料的完整性和一致性. •事務就是一系列的動作, 它們被當做一個單獨的工作單元. 這些動作要麼全部完成, 要麼全部不起作用 •事務的四個關鍵屬性(ACID) –原子性(atomicity): 事務是一個
spring深入學習(二十三) IOC 之 bean 的初始化
一個 bean 經歷了 createBeanInstance() 被創建出來,然後又經過一番屬性注入,依賴處理,歷經千辛萬苦,千錘百煉,終於有點兒 bean 例項的樣子,能堪大任了,只需要經歷最後一步就破繭成蝶了。這最後一步就是初始化,也就是 initializeBea
Spring Security(二十三):6.5 The Default AccessDecisionManager(預設接入策略管理)
This section assumes you have some knowledge of the underlying architecture for access-control within Spring Security. If you don’t you can skip it and com
Spring 學習(二十)——用基於 XML 配置檔案的方式來配置 AOP
•除了使用 AspectJ 註解宣告切面, Spring 也支援在 Bean 配置檔案中宣告切面. 這種宣告是通過 aop schema 中的 XML 元素完成的. •正常情況下, 基於註解的宣告要優先於基於 XML 的宣告. 通過 AspectJ 註解, 切面可以與 AspectJ 相容, 而
Python學習(二十三)—— 前端基礎之jQuery
官方 現在 展開 可能 獲取 不能 col js文件 層級 轉載自https://q1mi.github.io/Blog/2017/07/10/about_jQuery/ 一、jQuery入門 jQuery是一個輕量級的、兼容多瀏覽器的JavaScript庫。 jQuer
JMeter學習(二十三)關聯
話說LoadRunner有的一些功能,比如:引數化、檢查點、集合點、關聯,Jmeter也都有這些功能,只是功能可能稍弱一些,今天就關聯來講解一下。 JMeter的關聯方法有兩種:後置處理器-正則表示式提取器與XPath Extractor。 一、正則表示式提取器 1、新
opencv學習(二十三):形態學操作
影象的形態學處理 數學形態學(Mathematical morphology)是一門 建立在格論和拓撲學基礎之上的影象分析學科,是數學形態學影象處理的基本理論。其基本的運算包括:腐蝕和膨脹、開運算和閉
Spring 學習(十七)——Spring AOP之返回通知、異常通知和環繞通知
返回通知 •無論連線點是正常返回還是丟擲異常, 後置通知都會執行. 如果只想在連線點返回的時候記錄日誌, 應使用返回通知代替後置通知. 在返回通知中訪問連線點的返回值 •在返回通知中, 只要將 returning 屬性新增到 @AfterReturning 註解中
Spring 學習(十六)——Spring AOP之前置通知和後置通知
spring aop 1)加入jar包 com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.R
Spring學習(十五)Spring Bean 的5種作用域介紹
Spring Bean 中所說的作用域,在配置檔案中即是“scope” 在面向物件程式設計中作用域一般指物件或變數之間的可見範圍。 而在Spring容器中是指其建立的Bean物件相對於其他Bean物件
JavaWeb學習(二十三)———Filter(過濾器)
一、Filter簡介 Filter也稱之為過濾器,它是Servlet技術中最激動人心的技術,WEB開發人員通過Filter技術,對web伺服器管理的所有web資源:例如Jsp, Servlet, 靜態圖片檔案或靜態 html 檔案等進行攔截,從而實現一些特殊的功能。例如實現URL級別的許可
Spring學習(十四)Spring Bean 的3種例項化方法介紹
Spring IoC容器如何例項化Bean呢? 傳統應用程式可以通過new和反射方式進行例項化Bean。而Spring IoC 容器則需要根據Bean定義裡的配置元資料使用反射機制來建立Bean。在
Spring學習(十六)Spring Bean內容模型介紹
本次主要介紹Spring Bean的內容模型,通過對內容模型的瞭解使開發者能夠對Spring Bean有一個全域性的認識。關於Spring Bean的詳細資訊可以參考spring-bea
spring學習(十一)——spring官方文件閱讀(5.0.7)——spring的@Bean與@Configuration註解
@Bean與@Configuration註解 @Bean註解用於方法上,返回的例項將由Spring IOC管理,當在@Configuration註解的類中使用@Bean註解時,@Bean相當於<bean/>元素,@Configuration相當於<bean
Bootstarp學習(二十三)模態彈出框(Modals)
這一小節我們先來講解一個“模態彈出框”,外掛的原始檔:modal.js。 右側程式碼編輯器(30行)就是單獨引入 bootstrap 中釋出出的“modal.js”檔案。 樣式程式碼: ? LESS版本:modals.less ? Sass版本:_mod
C++學習(二十三)(C語言部分)之 指針4
個數字 函數類型 圖片 有意義 大小 堆排 傳參 不能 etc 指針 指針 存放地址 只能存放地址 使用 &取地址運算符 *取值 解引用運算符 malloc 申請堆內存 free釋放堆內存 1.1 指針 存放的地址(變量地址 常量區的地址 堆區內存
spring學習(二)配置bean的一些相關知識
相關 idt 工作內容 分享 配置文件 ext 處理器 lac 數據 1.bean的作用域問題 bean的scope屬性可以用來限定bean的作用域,有四個取值singleton((默認) prototype(常用) request session分別表示不同的範圍
Spring學習(二)| Bean配置
文章目錄 1. 什麼是IoC 2. 配置Bean 2.1 配置形式 2.1.1 基於XML檔案的形式 2.1.2 基於註解的方式 2.1.2.1 元件掃描
Spring Cloud系列(二十三) API閘道器服務Spring Cloud Zuul(Finchley.RC2版本)
為什麼使用Spring Cloud Zuul? 通過前幾章的介紹,我們對於Spring Cloud Netflix 下的核心元件已經瞭解了大半,利用這些元件我們已經可以構建一個簡單的微服務架構系統,比如通過使用Spring Cloud Eureka實現高可用的服務註冊中