7 -- Spring的基本用法 -- 10... 獲取其他Bean的屬性值;獲取Field值;獲取任意方法的返回值


    7.10 高級依賴關系配置

      組件與組件之間的耦合,采用依賴注入管理;但基本類型的成員變量值,應直接在代碼中設置。

      Spring支持將任意方法的返回值、類或對象的Field值、其他Bean的getter方法返回值,直接定義成容器中的一個Bean。

      Spring框架的本質是,開發者在Spring配置文件中使用XML元素進行配置,實際驅動Spring執行響應的代碼。例如:

      ⊙ 使用<bean.../>元素,實際啟動Spring執行無參數或有參數的構造器,或者調用工廠方法創建Bean。

      ⊙ 使用<property.../>元素,實際驅動Spring執行一次setter方法。

      但Java程序還可能有其他類型的語句,如調用getter方法、調用普通方法、訪問類或對象的Field,而Spring也為這種語句提供了對應的配置語法。例如:

      ⊙ 調用getter方法 :使用PropertyPathFactoryBean

      ⊙ 訪問類或對象的Field值 : 使用FieldRetrievingFactoryBean。

      ⊙ 調用普通方法 : 使用MethodInvokingFactoryBean。

      7.10.1 獲取其他Bean的屬性值

        PropertyPathFactoryBean用來獲取目標Bean的屬性值(實際上就是它的getter方法的返回值),獲得的值可注入給其他Bean,也可直接定義成新的Bean。

        使用PropertyPathFactoryBean來調用其他Bean的getter方法需要指定如下信息:

        ⊙ 調用那個對象。有PropertyPathFactoryBean的setTargetObject(Object targetObject) 方法指定。

        ⊙ 調用那個getter方法。有PropertyPathFactoryBean的setPropertyPath(String propertyPath)方法指定。

        Class : Person

package edu.pri.lime._7_10_1.bean;

public class Person {

    private String name;
    private int age;
    private Person son;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person getSon() {
        System.out.println("father:getSon");
        return son;
    }
    public void setSon(Person son) {
        this.son = son;
    }
        
}

        XML : 

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd語義約束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="father" class="edu.pri.lime._7_10_1.bean.Person">
        <property name="name" value="lime" />
        <property name="age" value="45" />
        <property name="son">
            <bean class="edu.pri.lime._7_10_1.bean.Person">
                <property name="name" value="oracle"/>
                <property name="age" value="20" />
            </bean>
        </property>
    </bean>

    <bean id="mother" class="edu.pri.lime._7_10_1.bean.Person">
        <property name="name" value="liyu"/>
        <property name="age" value="43"/>
        <!-- 可以注入另一個Bean中 -->
        <property name="son">
            <bean class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
                <!-- 確定目標Bean,指定son Bean來自哪個Bean的getter方法 -->
                <property name="targetBeanName" value="father"/>
                <!-- 指定son Bean來自目標Bean的哪個getter方法,age代表getAge() -->
                <property name="propertyPath" value="son"/>
            </bean>
        </property>
    </bean>
    
    <!-- 可以直接定義成容器中的Bean實例 -->
    <bean id="son" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
        <property name="targetBeanName" value="father"/>
        <property name="propertyPath" value="son"/>
    </bean>
</beans>

        Class : SpringTest

package edu.pri.lime._7_10_1.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import edu.pri.lime._7_10_1.bean.Person;

public class SpringTest {
    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_10_1.xml");
        
//        可以注入到另一個Bean中
        Person mother = ctx.getBean("mother",Person.class);
        System.out.println(mother.toString());
        System.out.println(mother.getSon().toString());
        
        Person father = ctx.getBean("father",Person.class);
        System.out.println(father.toString());
        System.out.println(father.getSon().toString());
        
//        可以定義成容器中的Bean實例
        Person son = ctx.getBean("son",Person.class);
        System.out.println(son.toString());
    }
}

        Console : 

father:getSon
edu.pri.lime._7_10_1.bean.Person@776aec5c
father:getSon
edu.pri.lime._7_10_1.bean.Person@1d296da
edu.pri.lime._7_10_1.bean.Person@7c7a06ec
father:getSon
edu.pri.lime._7_10_1.bean.Person@1d296da
father:getSon
edu.pri.lime._7_10_1.bean.Person@1d296da

        程序調用son實例的setSon方法的參數並不是直接指定的,而是將容器中另一個Bean實例的屬性值(getter方法的返回值)作為setSon()方法的參數。注意son Bean的地址是一樣的。

        PropertyPathFactoryBean工廠Bean負責獲取容器中另一個Bean的屬性值(getter方法的返回值)。

        為PropertyPathFactoryBean的setPropertyPath()方法指定屬性表達式時,還支持使用復合屬性的形式,例如:想獲取person Bean的getSon().getAge()的返回值,可采用son.age的形式。

        XML : 

    <!-- 將基本數據類型的屬性值定義成Bean實例 -->
    <bean id="theAge" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
        <!-- 確定目標Bean,表明theAge Bean來自哪個Bean的getter方法的返回值 -->
        <property name="targetBeanName" value="mother"/>
        <!-- 使用復合屬性來指定getter方法。son.age代表getSon().getAge() -->
        <property name="propertyPath" value="son.age"/>
    </bean>

        目標Bean既可以是容器中已有的Bean實例,也可以是嵌套Bean實例。

        使用嵌套Bean實例時,指定目標Bean使用targetObject屬性,其他時候使用targetBeanName屬性

        XML :

   <!-- 將基本數據類型的屬性值定義成Bean實例 -->
    <bean id="hisAge" class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
        <!-- 確定目標Bean,表明hisAge Bean來自哪個Bean的屬性。此處采用嵌套Bean定義目標Bean -->
        <property name="targetObject">
            <!-- 目標Bean不是容器中已經存在的Bean,而是如下的嵌套Bean -->
            <!-- 使用嵌套Bean實例時,指定目標Bean使用targetObject屬性,其他時候使用targetBeanName屬性 -->
            <bean class="edu.pri.lime._7_10_1.bean.Person">
                <property name="age" value="30" />
            </bean>
        </property>
        <!-- 指定hisAge Bean來自目標Bean 的哪個getter方法,age代表getAge() -->
        <property name="propertyPath" value="age"/>
    </bean>

        <util:property-path.../>元素可作為PropertyPathFactoryBean的簡化配置,使用該元素時可指定如下兩個屬性:

          ⊙ id : 該屬性指定將getter方法的返回值定義成名為id的Bean的實例。

          ⊙ path : 該屬性指定將哪個Bean實例、哪個屬性(支持復合屬性)暴露出來。

        如果需要使用<util:property-path.../>元素,必須在Spring配置文件中導入util:命名空間。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

        herAge 可簡化為:

<util:property-path id="herAge" path="father.son.age"/>

      7.10.2 獲取Field值

        通過FieldRetrievingFactoryBean類,可訪問類的靜態Field或對象的實例Field值。

        FieldRetrievingFactoryBean 獲得指定Field的值之后,即可將獲取的值注入其他Bean,也可直接定義成Bean。

        使用FieldRetrievingFactoryBean訪問Field值可分為兩種情形。

        ① 如果要訪問的Field是靜態Field,則需要指定:

          ⊙ 調用哪個類。由FieldRetrievingFactoryBean的setTargetClass(String targetClass)方法指定。

          ⊙ 訪問哪個Field。由FieldRetrievingFactoryBean的setTargetField(String targetField)方法指定。

        ② 如果要訪問的Field是實例Field,則需要指定:

          ⊙ 調用哪個對象。由FieldRetrievingFactoryBean的setTargetObject(Object targetObject)方法指定。

          ⊙ 訪問哪個Field。由FieldRetrievingFactoryBean的setTargetField(String targetField)方法指定。

        對於FieldRetrievingFactory訪問實例Field的情形,需要實例Field以public修飾,這種情況及其少見。

         XML : 

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd語義約束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 將指定類的靜態Field值定義成容器中的Bean實例 -->
    <bean id="theAge" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <!-- targetClass指定訪問哪個目標類 -->
        <property name="targetClass" value="java.sql.Connection"/>
        <!-- targetField指定要訪問的Field名 -->
        <property name="targetField" value="TRANSACTION_SERIALIZABLE"/>
    </bean>

</beans>

        Class : SpringTest

package edu.pri.lime._7_10_2.main;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {

    public static void main(String[] args){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_10_2.xml");
        {
            Integer theAge = ctx.getBean("theAge",Integer.class);
            System.out.println(theAge);
        }
    }
}

        Console : 

一月 14, 2017 6:52:01 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2752f6e2: startup date [Sat Jan 14 18:52:01 CST 2017]; root of context hierarchy
一月 14, 2017 6:52:01 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [app_7_10_2.xml]
8

        FieldRetrievingFactoryBean還提供了一個setStaticField(String staticField)方法,該方法可同時指定獲取哪個類的哪個靜態Field值。

   <bean id="hisAge" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
        <property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
    </bean>

         <util:constant.../>元素(需要導入util:命名空間)可作為FieldRetrievingFactoryBean訪問靜態Field的簡化配置。

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

        使用<util:constant.../>元素需指定如下兩個屬性:

        ⊙ id : 該屬性指定就愛那個靜態Field的值定義成名為id 的Bean實例。

        ⊙ static-field : 該屬性指定訪問哪個類的哪個靜態Field。

        herAge可簡化為如下配置:

<util:constant id="herAge" static-field="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>

      7.10.3 獲取任意方法的返回值

        通過MethodInvokingFactoryBean工程Bean,可調用任意類的類方法,也可調用任意對象的實例方法,如果調用的方法有返回值,即可將該指定方法的返回值定義成容器中的Bean,也可將指定方法的返回值注入給其他Bean。

        使用MethodInvokingFactoryBean來調用任意方法時,可分為兩種情形。

        ① 如果希望調用的方法是靜態方法,則需要指定:

          ⊙ 調用哪個類。通過MethodInvokingFactoryBean的setTargetClass(String targetClass)方法指定。

          ⊙ 調用哪個方法。通過MethodInvokingFactoryBean的setTargetMethod(String targetMethod)方法指定。

          ⊙ 調用方法的參數。通過MethodInvokingFactoryBean的setArguments(Object[] arguments)方法指定。

            如果希望調用的方法無須參數,則可以省略該配置。

        ② 如果希望調用的方法是實例方法,則需要指定:

          ⊙ 調用哪個對象。通過MethodInvokingFactoryBean的setTargetObject(Object targetObject)方法指定。

          ⊙ 調用哪個方法。通過MethodInvokingFactoryBean的setTargetMethod(String targetMethod)方法指定。

          ⊙ 調用方法的參數。通過MethodInvokingFactoryBean的setArguments(Object[] arguments)方法指定。

            如果希望調研那個的方法無須參數,則可以省略該配置。

        Class : SpringTest

package edu.pri.lime._7_10_3.main;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class SpringTest {

    public static void main(String[] args){
        JFrame win = new JFrame("我的窗口");
        JTextArea jta = new JTextArea(7,40);
        win.add(new JScrollPane(jta));
        JPanel jp = new JPanel();
        win.add(jp,BorderLayout.SOUTH);
        JButton jb1 = new JButton("確定");
        jp.add(jb1);
        JButton jb2 = new JButton("取消");
        jp.add(jb2);
        win.pack();
        win.setVisible(true);
    }
}

        使用配置文件XML : 

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd語義約束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd">

<!--     
    下面配置相當於如下Java代碼:
    JFrame win = new JFrame("我的窗口");
    win.setVisible(true); -->
    <bean id="win" class="javax.swing.JFrame">
        <constructor-arg value="我的窗口" type="java.lang.String"/>
        <property name="visible" value="true"/>
    </bean>
<!--     
    下面配置相當於如下Java代碼:
    JTextArea jta = JTextArea(7,40); -->
    <bean id="jta" class="javax.swing.JTextArea">
        <constructor-arg value="7"/>
        <constructor-arg value="40"/>
    </bean>
<!--     
    使用MethodInvokingFactoryBean驅動Spring調用普通方法下面配置相當於如下Java代碼:
    win.add(new JScrollPane(jta)); -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="win"/>
        <property name="targetMethod" value="add"/>
        <property name="arguments">
            <array>
                <bean class="javax.swing.JScrollPane">
                    <constructor-arg ref="jta"/>
                </bean>
            </array>
        </property>
    </bean>
<!--     
    下面配置相當於如下Java代碼:
    JPanel jp = new JPanel(); -->
    <bean id="jp" class="javax.swing.JPanel"/>
<!--     
    使用MethodInvokingFactoryBean驅動Spring調用普通方法
    下面配置相當於如下Java代碼
    win.add(jp,BorderLayout.SOUTH); -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="win"/>
        <property name="targetMethod" value="add"/>
        <property name="arguments">
            <array>
                <ref bean="jp"/>
                <bean class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
                    <property name="targetClass" value="java.awt.BorderLayout"/>
                    <property name="targetField" value="SOUTH"/>
                </bean>
                <!-- 
                <util:constant static-field="java.awt.BorderLayout.SOUTH"/>
                 -->
            </array>
        </property>
    </bean>
<!--     
    下面配置相當於如下Java代碼:
    JButton jb1 = new JButton("確定"); -->
    <bean id="jb1" class="javax.swing.JButton">
        <constructor-arg value="確定" type="java.lang.String"/>
    </bean>
<!--     
    使用MethodInvokingFactoryBean驅動Spring調用普通方法
    下面配置相當於如下Java代碼:
    jp.add(jb1); -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="jp"/>
        <property name="targetMethod" value="add"/>
        <property name="arguments">
            <array>
                <ref bean="jb1"/>
            </array>
        </property>
    </bean>
<!--     
    下面配置相當於如下Java代碼:
    JButton jb2 = new JButton("取消"); -->
    <bean id="jb2" class="javax.swing.JButton">
        <constructor-arg value="取消" type="java.lang.String"/>
    </bean>
<!--     
    使用MethodInvokingFactoryBean驅動Spring調用普通方法
    下面配置相當於如下Java代碼:
    jp.add(jb2); -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="jp"/>
        <property name="targetMethod" value="add"/>
        <property name="arguments">
            <array>
                <ref bean="jb2"/>
            </array>
        </property>
    </bean>
<!--     
    使用MethodInvokingFactoryBean驅動Spring調用普通方法:
    下面配置相當於如下Java代碼:
    win.pack(); -->
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="win"/>
        <property name="targetMethod" value="pack"/>
    </bean>

</beans>

        Class : XMLTest

package edu.pri.lime._7_10_3.main;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XMLTest {
    @SuppressWarnings("resource")
    public static void main(String[] args){
        new ClassPathXmlApplicationContext("app_7_10_3.xml");
    }
}

        Spring框架的本質其實就是通過XML配置來執行Java代碼,因此幾乎可以把所有的Java代碼放到Spring配置文件中管理。

        歸納:

          ⊙ 調用構造器創建對象(包括使用工廠方法創建對象),用<bean.../>元素。

          ⊙ 調用setter方法,用<property.../>元素。

          ⊙ 調用getter方法,用PropertyPathFactoryBean或<util:property-path.../>元素。

          ⊙ 調用普通方法,用MethodInvokingFactoryBean工廠Bean。

          ⊙ 獲取Field值,用FieldRetrievingFactoryBean或<util:constant.../>元素。

        一般來說,應該將如下兩類信息放到XML配置文件中管理:

        ⊙ 項目升價、維護時經常需要改動的信息。

        ⊙ 控制項目內個組件耦合關系的代碼。

        這樣就體現了Spring IoC 容器的作用:將原來使用Java 代碼管理的耦合關系,提取到XML中進行管理,從而降低了各組件之間的耦合,提高了軟件系統的可維護性。

  

啦啦啦

      

       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM