系统学习Spring之Spring in action(四)
每日一叨:
时间不早了,就不啰嗦了,直接进入正题.
文章导读:
1.通过SpEL表达式装配自面量
2.通过SpEL装配实例化的bean与获取实例化bean的属性进行装配
3.通过SpEL访问class-Scope的静态方法和常量
知识点:
到现在为止,学过的两种装配properties和constructor-arg都是被静态的定义在Spring configuration 的xml文件中.除了静态的装配,Spring
提供了通过Spring表达式进行动态装配.静态装配和动态装配的不同之处:静态装配都是预先定义在Spring Configuration配置文件中,在加载配置文件
之前就已经定义完成,而动态装配则是直到加载配置文件的时候(Runtime)才知道需要装配些什么.
1.通过SpEL表达式装配自面量
自面量:简单的说就是可以直接描述自己的量,比如"LiuShuai" ,1 ,2.5 ,1e4,true 它们都是自面量.
装配自面量比较鸡肋,SpEL表达式的优势不在装配自面量上,下面我们来看如果用SpEl表达式装配自面量:
创建一个字面量容器类:
public class LiteralValue { //整数字面量 private int intValue; //双精度型小数字面量 private double doubleValue; //科学记数法数字面量 private double scientificValue; //单精度型小数字面量 private float floatValue; //布尔类型字面量 private boolean booleanValue; //字符串类型字面量 private String stringValue; public void showLiteralValue(){ System.out.println("整数字面量:" + this.intValue +"\n双精度型小数字面量:"+ this.doubleValue + "\n科学记数法数字面量:" + this.scientificValue + "\n单精度型小数字面量:" +this.floatValue + "\n布尔类型字面量:" + this.booleanValue + "\n字符串类型字面量:" + this.stringValue); } //省略getter和setter }
这是未使用SpEL装配自面量的Spring Configuration配置.
<bean id="literalValue" class="com.ricky.zero.pojo.LiteralValue"> <property name="intValue" value="21"></property> <property name="doubleValue" value="52.0"></property> <property name="scientificValue" value="1e4"></property> <property name="floatValue" value="13.0f"></property> <property name="booleanValue" value="true"></property> <property name="stringValue" value="刘帅"></property> </bean>
这是使用SpEl装配自面量的Spring Configuration配置.
<bean id="literalValue" class="com.ricky.zero.pojo.LiteralValue"> <property name="intValue" value="#{21}"></property> <property name="doubleValue" value="#{52.0}"></property> <property name="scientificValue" value="#{1e4}"></property> <property name="floatValue" value="#{13.0f}"></property> <property name="booleanValue" value="#{true}"></property> <property name="stringValue" value="#{'刘帅'}"></property> </bean>
运行测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); LiteralValue literalValue = (LiteralValue)ctx.getBean("literalValue"); literalValue.showLiteralValue();
测试结果都是:
整数字面量:21
双精度型小数字面量:52.0
科学记数法数字面量:10000.0
单精度型小数字面量:13.0
布尔类型字面量:true
字符串类型字面量:刘帅
现在看来,用SpEL表达式来装配还有不用SpEL装配简单,而且结果都是一样的.因为用SpEL装配字面量本来就不是SpEL的强项,下面继续深入了解SpEL.
2.通过SpEL装配实例化的bean与获取实例化bean的属性进行装配
创建一个歌手类.
public class Singer { //歌手的名字 private String name; //歌手最喜欢唱的歌 private String favoriteSong; //getter和setter省略 }
创建一个程序员类:
public class Programer { //程序员最喜欢的歌 private String favoriteSong; //程序员最喜欢的歌手 private Singer singer; public void showResult(){ System.out.println("程序员最喜欢的歌手是:" + this.singer.getName() + "\n程序员最喜欢的歌是:" + this.favoriteSong); } //getter和setter省略 }
Spring Configuration配置
<bean id="singer" class="com.ricky.zero.pojo.Singer"> <property name="name" value="Lene Marlin"></property> <property name="favoriteSong" value="A Place Nearby"></property> </bean> <bean id="programer" class="com.ricky.zero.pojo.Programer"> <property name="favoriteSong" value="#{singer.favoriteSong}"></property> <property name="singer" value="#{singer}"></property> </bean>
以前用properties标签注入已经实例的bean要用ref属性,现在用SpEL后,可以不用ref属性,直接使用value属性,用法value="#{beanId}" 这样就把已经实例
的bean注入到properties里了.SpEL还可以直接调用已经实例化的对象的属性.用法#{beanId.propertiesName}
SpEL还提供了通过已经实例的对象方法返回值进行注入.
这是通过方法返回值来注入:
<bean id="singer" class="com.ricky.zero.pojo.Singer"> <property name="name" value="Lene Marlin"></property> <property name="favoriteSong" value="A Place Nearby"></property> </bean> <bean id="programer" class="com.ricky.zero.pojo.Programer"> <property name="favoriteSong" value="#{singer.getFavoriteSong()}"></property> <property name="singer" value="#{singer}"></property> </bean>
运行测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); Programer programer = (Programer)ctx.getBean("programer"); programer.showResult();
测试结果:
程序员最喜欢的歌手是:Lene Marlin
程序员最喜欢的歌是:A Place Nearby
如果我想取英文全部小心的歌名,只需要修改配置文件,修改如下:
<bean id="singer" class="com.ricky.zero.pojo.Singer"> <property name="name" value="Lene Marlin"></property> <!-- <property name="favoriteSong" value="A Place Nearby"></property> --> </bean> <bean id="programer" class="com.ricky.zero.pojo.Programer"> <property name="favoriteSong" value="#{singer.getFavoriteSong().toLowerCase()}"></property> <property name="singer" value="#{singer}"></property> </bean>
测试运行后,得到结果如下:
抛错了: Attempted to call method toLowerCase() on null context object.
不好意思,是我的原因,不小心把ID为singer的bean中的name为favoriteSong的properties注释了.导致Spring 上下文对象企图将用null值
调用toLowerCase方法.这个错误类似于NullPointerException.如何防止抛错.下面介绍一个操作符 ?.
那我就将错就错的解决下这个问题.
通过?.操作符来确保操作符的左值不为null,若左值为空则不执行操作符右侧操作.相反左值不为null,则继续进行右侧操作.
测试下:
<bean id="singer" class="com.ricky.zero.pojo.Singer"> <property name="name" value="Lene Marlin"></property> <!-- <property name="favoriteSong" value="A Place Nearby"></property> --> </bean> <bean id="programer" class="com.ricky.zero.pojo.Programer"> <property name="favoriteSong" value="#{singer.getFavoriteSong()?.toLowerCase()}"></property> <property name="singer" value="#{singer}"></property> </bean>
运行测试:测试结果:
程序员最喜欢的歌手是:Lene Marlin
程序员最喜欢的歌是:null
现在不会抛错了 ?. 操作符 确保左值为null不继续执行右侧操作成功.
现在我们把注释清除,即使以后实例对象返回null也不会抛错了.
<bean id="singer" class="com.ricky.zero.pojo.Singer"> <property name="name" value="Lene Marlin"></property> <property name="favoriteSong" value="A Place Nearby"></property> </bean> <bean id="programer" class="com.ricky.zero.pojo.Programer"> <property name="favoriteSong" value="#{singer.getFavoriteSong()?.toLowerCase()}"></property> <property name="singer" value="#{singer}"></property> </bean>
运行测试:测试结果:
程序员最喜欢的歌手是:Lene Marlin
程序员最喜欢的歌是:a place nearby
测试结果:歌名转换小写成功.
3.通过SpEL访问class-Scope的静态方法和常量
最笨的方法是直接把这个对象装配到properties中,但SpEL提供了一个更方便的操作符T().举一个常用的类java.lang.Math.下面来演示如何时通过
T()操作符来调用java.lang.Math中的常量和静态方法.
public class UseT { //圆周率PI private double pi; //随机数 private double randomNumber; public void showResult(){ System.out.println("圆周率:" + this.pi + "\n随机数:" + this.randomNumber); } //省略getter和setter }
<bean id="useT" class="com.ricky.zero.pojo.UseT"> <property name="pi" value="#{T(java.lang.Math).PI}"></property> <property name="randomNumber" value="#{T(java.lang.Math).random()}"></property> </bean>
测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml"); UseT useT = (UseT)ctx.getBean("useT"); useT.showResult();
测试结果:
圆周率:3.141592653589793
随机数:0.13167670721683722
注意:由于随机数是随机生成的,你的随机数和我的测试结果中随机数不一致是正常现象.
以后可以通过SpEL调用类范围下的静态方法和常量用#{T(包名+类名)}
SpEL简单用法到这里就结束了,SpEL还支持#(这里可以进行算术运算,逻辑运算,关系运算,三目运算,正则表达式匹配,访问与过虑集合).更多用法,
请参考Spring官方文档.
特别注意下,在XML配置文件中不能直接使用<> <= >= == 而使用对应的文本.例eq lt le gt ge.
--------------------------------申明----------------------------
本文可以免费阅读以及转载,转载时请注明出处.
本人邮箱:Ricky_LS@163.com
Thank you for your corporation.