zoukankan      html  css  js  c++  java
  • 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中进行管理,从而降低了各组件之间的耦合,提高了软件系统的可维护性。

      

    啦啦啦

          

           

  • 相关阅读:
    ES6中的解构赋值
    一·京京得水
    localStorage,sessionStorage和cookie的区别
    mondodb和mysql的区别
    Win10 x64连接Oracle
    JFinal项目实践(了如股掌)7
    JFinal项目实践(了如股掌)6
    JFinal项目实践(了如股掌)5
    JFinal项目实践(了如股掌)4
    JFinal项目实践(了如股掌)3
  • 原文地址:https://www.cnblogs.com/ClassNotFoundException/p/6285905.html
Copyright © 2011-2022 走看看