系统学习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.

  

 

posted @ 2013-03-22 00:54  养家糊口  阅读(617)  评论(0编辑  收藏  举报