Spring還提供了更靈活的注入方式,那就是Spring表達式,實際上Spring EL遠比以上注入方式強大,我們需要學習它。Spring EL擁有很多功能。
使用Bean的id來引用Bean。
•調用指定對象的方法和訪問對象的屬性。
•進行運算。
•提供正則表達式進行匹配。
•集合配置。
這些都是Spring表達式的內容,使用Spring表達式可以獲得比使用Properties文件更為強大的裝配功能,只是有時候為了方便測試可以使用Spring EL定義的解析類進行測試,為此我們先來認識它們。
Spring EL相關的類
簡要介紹Spring EL的相關類,以便我們進行測試和理解。首先是ExpressionParser接口,它是一個表達式的解析接口,既然是一個接口,那么它就不具備任何具體的功能,顯然Spring會提供更多的實現類
代碼清單:舉例說明Spring EL的使用
//表達式解析器 ExpressionParser parser = new SpelExpressionParser(); // 設置表達式 Expression exp = parser.parseExpression("'hello world'"); String str = (String) exp.getValue(); System.out.println(str); //通過EL訪問普通方法 exp = parser.parseExpression("'hello world'.charAt(0)"); char ch = (Character) exp.getValue(); System.out.println(ch); //通過EL訪問的getter方法 exp = parser.parseExpression("'hello world'.bytes"); byte[] bytes = (byte[]) exp.getValue(); System.out.println(bytes); //通過EL訪問屬性,相當於"hello world".getBytes().length exp = parser.parseExpression("'hello world'.bytes.length"); int length = (Integer) exp.getValue(); System.out.println(length); exp = parser.parseExpression("new String('abc')"); String abc = (String) exp.getValue(); System.out.println(abc); //表達式解析器 ExpressionParser parser = new SpelExpressionParser(); //創建角色對象 Role2 role = new Role2(1L, "role_name", "note"); Expression exp = parser.parseExpression("note"); //相當於從role中獲取備注信息 String note = (String) exp.getValue(role); System.out.println(note); //變量環境類,並且將角色對象role作為其根節點 EvaluationContext ctx = new StandardEvaluationContext(role); //變量環境類操作根節點 parser.parseExpression("note").setValue(ctx, "new_note"); //獲取備注,這里的String.class指明,我們希望返回的是一個字符串 note = parser.parseExpression("note").getValue(ctx, String.class); System.out.println(note); //調用getRoleName方法 String roleName = parser.parseExpression("getRoleName()").getValue(ctx, String.class); System.out.println(roleName); //新增環境變量 List<String> list = new ArrayList<String>(); list.add("value1"); list.add("value2"); //給變量環境增加變量 ctx.setVariable("list", list); //通過表達式去讀/寫環境變量的值 parser.parseExpression("#list[1]").setValue(ctx, "update_value2"); System.out.println(parser.parseExpression("#list[1]").getValue(ctx));
EvaluationContext使用了它的實現類StandardEvaluationContext,進行了實例化,在構造方法中將角色對象傳遞給它了,那么估值內容就會基於這個類進行解析。所以后面表達式的setValue和getValue方法都把這個估值內容傳遞進去,這樣就能夠讀/寫根節點的內容了,並且通過getRole()的例子,還可以知道它甚至能夠支持方法的調用。為了更加靈活,估值內容還支持了其他變量的新增和操作,正如代碼中創建了一個List,並且把List用估值內容的setVariable方法設置,其鍵為"list",這樣就允許我們在表達式里面通過#list去引用它,而給出的下標1,則是代表引用List的第二個元素(list是以下標0標識第一個元素的)。
上面介紹了Spring具有對表達式的解析功能,Spring EL最重要的功能就是對Bean屬性進行注入,讓我們以注解的方式為主去學習它們。
Bean的屬性和方法
使用注解的方式需要用到注解@Value,在屬性文件的讀取中使用的是“$”,而在Spring EL中則使用“#”。下面以角色類為例進行討論,我們可以這樣初始化它的屬性,如代碼清單所示。
代碼清單:使用Spring EL初始化角色類
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component("role2") public class Role2 { //賦值long型 @Value("#{2}") private Long id; //字符串賦值 @Value("#{'role_name_2'}") private String roleName; //字符串賦值 @Value("#{'note_2'}") private String note; }
代碼清單:通過Spring EL引用role的屬性,調用其方法
@Component("elBean") public class ElBean { //通過beanName獲取bean,然后注入 @Value("#{role2}") private Role2 role2; //獲取bean的屬性id @Value("#{role2.id}") private Long id; //調用bean的getNote方法,獲取角色名稱 // @Value("#{role.getNote().toString()}") @Value("#{role2.getNote()?.toString()}") private String note; @Value("#{T(Math).PI}") private double pi; @Value("#{T(Math).random()}") private double random; @Value("#{role.id+1}") private int num; }
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig3.class); Role2 role2 = context.getBean(Role2.class); System.out.println(role2.toString()); ElBean elBean = context.getBean(ElBean.class); System.out.println(elBean.toString());
使用類的靜態常量和方法
有時候我們可能希望使用一些靜態方法和常量,比如圓周率π,而在Java中就是Math類的PI常量了,需要注入它十分簡單,在ElBean中如同下面一樣操作就可以了:
@Value("#{T(Math).PI}")
private double pi;
這里的Math代表的是java.lang.*包下的Math類。當在Java代碼中使用該包是不需要先使用import關鍵字引入的,對於Spring EL也是如此。如果在Spring中使用一個非該包的內容,那么要給出該類的全限定名,需要寫成類似這樣:
@Value("#{T(java.lang.Math).PI}")
private double pi;
同樣,有時候使用Math類的靜態方法去生產隨機數(0到1之間的隨機雙精度數字),這個時候就需要使用它的random方法了,比如:
@Value("#{T(Math).random()}")
private double random;
這樣就可以通過調用類的靜態方法加載對應的數據了。
Spring EL運算
上面討論了如何獲取值,除此之外Spring EL還可以進行運算,比如在ElBean上增加一個數字num,其值默認為要求是角色編號(id)+1,那么我們就可以寫成:
@Value("#{role.id+1}")
private int num;
有時候“+”運算符也可以運用在字符串的連接上,比如下面的這個字段,把角色對象中的屬性roleName和note相連:
@Value("#{role.roleName + role.note}")
private String str;
這樣就能夠得到一個角色名稱和備注相連接的字符串。比較兩個值是否相等,比如角色id是否為1,角色名稱是否為"role_name_001"。數字和字符串都可以使用“eq”或者“==”進行相等比較。除此之外,還有大於、小於等數學運算,比如:
@Value("#{role.id == 1}")
private boolean equalNum;
@Value("#{role.note eq 'note_1'}")
private boolean eqaulString;
@Value("#{role.id > 2}")
private boolean greater;
@Value("#{role.id < 2}")
private boolean less;
在Java中,也許你會懷念三目運算,比如,如果角色編號大於1,那么取值5,否則取值1,那么在Java中可以寫成:
int max = (role.getId()>1? 5:1);
如果角色的備注為空,我們給它一個默認的初始值“note”,使用Java則寫成:
String defaultString = (role.getNote() == null? "hello" : role.getNote());
下面讓我們通過String EL去實現上述的功能。
@Value("#{role.id > 1 ? 5 : 1}")
private int max;
@Value("#{role.note?: 'hello'}")
private String defaultString;
實際上Spring EL的功能遠不止這些,上面只介紹了一些最基礎、最常用的功能,熟練運用它還需要讀者們多動手實踐。
文章來源:ssm10.10