以前工做時,公司封裝的jar包中,使用了spring的MethodInvokingFactoryBean注入方式,以前沒見過這種使用方式。搜索了一下,找到一篇比較好的Blog,閱讀並測試了一遍,挺好!java
https://my.oschina.net/itblog/blog/206481spring
直接上測試代碼:測試
實體類:this
Person.net
package com.pa.spring.test.inject; public class Person { private int age; private Son son; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } }
Soncode
package com.pa.spring.test.inject; public class Son { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
參數類xml
InjectConstant對象
package com.pa.spring.test.inject; public class InjectConstant { public static String AAA = "2016"; public static String BBB = "2019"; public static int CCC = 11; public static int DDD = 18; public String eee = "19"; public String fff = "29"; public int ggg = 56; public int hhh = 15; }
方法調用類blog
ValueGeneratorget
package com.pa.spring.test.inject; public class ValueGenerator { public int getValue() { return 2; } public static int getStaticValue() { return 3; } public String getParamValue(String key,String value) { return key + " : " + value; } }
Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- ================================PropertyPathFactoryBean================================ --> <!-- 將一個類注入到另外一個類的屬性中 --> <bean id="person" class="com.pa.spring.test.inject.Person"> <property name="age" value="30" /> <property name="son"> <!-- 屬性son不是一個簡單值,而是Son類型,因此注入的時候就須要使用Son類型的Bean --> <bean class="com.pa.spring.test.inject.Son"> <property name="age" value="12" /> </bean> </property> </bean> <!-- 這個son的bean並不只是Son的實例,而是person bean的屬性 --> <bean id="son1" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"> <!-- 肯定目標Bean,代表son1來自哪一個Bean的組件 --> <property name="targetBeanName" value="person" /> <!-- 肯定屬性,代表son1來自目標Bean的哪一個屬性 --> <property name="propertyPath" value="son" /> </bean> <bean id="son2" class="com.pa.spring.test.inject.Son"> <!-- age屬性不是直接注入,而是將person中的son的age屬性賦值給son2的age屬性 --> <property name="age"> <!-- 注意這裏使用的是PropertyPathFactoryBean --> <bean id="person.son.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean" /> </property> </bean> <!-- ================================FieldRetrievingFactoryBean================================ --> <!-- 使用一個類的靜態屬性值注入到Son類的 age屬性中 --> <bean id="son3" class="com.pa.spring.test.inject.Son"> <property name="age"> <bean id="com.pa.spring.test.inject.InjectConstant.AAA" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" /> </property> </bean> <!-- 首先,age是一個Bean實例,能夠經過ApplicationContext#getBean(String name)取出 其次,age並無一個實體類與之對應 ,而是經過FieldRetrievingFactoryBean反射注入的 最後,使用targetClass屬性時,注入的類型是[靜態]的,類型未定 --> <bean id="age1" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"> <!-- targetClass指定Field所在的目標類 --> <property name="targetClass" value="com.pa.spring.test.inject.InjectConstant" /> <!-- targetField指定Field名 --> <property name="targetField" value="BBB" /> </bean> <!-- 簡寫形式,和上面的方式(age1)等價 --> <bean id="age2" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"> <!-- name的值是固定的,value指定哪一個類的哪一個[靜態]域值 --> <property name="staticField" value="com.pa.spring.test.inject.InjectConstant.CCC" /> </bean> <bean id="injectConstant" class="com.pa.spring.test.inject.InjectConstant"/> <!-- 和targetClass不一樣的是,使用targetObject時,注入的是[非靜態]屬性 從名字上也可猜想,靜態的和class對應,而實例的則和Object(對象)對應 因爲是非靜態的,因此首先須要存在一個對象(實例),在配置文件中反映出來的結果就是配置一個bean --> <bean id="age3" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"> <!-- targetClass指定Field所在目標類的實例 --> <property name="targetObject" ref="injectConstant" /> <!-- targetField指定Field名 --> <property name="targetField" value="eee" /> </bean> <!-- ================================MethodInvokingFactoryBean================================ --> <!-- 定義目標Bean,後面將會獲取該Bean的方法返回值 --> <bean id="valueGenerator" class="com.pa.spring.test.inject.ValueGenerator" /> <bean id="son4" class="com.pa.spring.test.inject.Son"> <property name="age"> <!-- 獲取方法返回值:調用valueGenerator的無參[非靜態]方法getValue --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="valueGenerator" /> <property name="targetMethod" value="getValue" /> </bean> </property> </bean> <bean id="son5" class="com.pa.spring.test.inject.Son"> <property name="age"> <!-- 獲取方法返回值:調用valueGenerator的無參[靜態]方法getStaticValue,和上述沒什麼區別 --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="valueGenerator" /> <property name="targetMethod" value="getStaticValue" /> </bean> </property> </bean> <!-- 簡寫形式,和上面的方式(son5)等價 --> <bean id="son6" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <!-- 使用staticMethod屬性,直接指定目標類的目標方法 --> <property name="staticMethod" value="com.pa.spring.test.inject.ValueGenerator.getStaticValue" /> </bean> <bean id="son7" class="com.pa.spring.test.inject.Son"> <property name="name"> <!-- 獲取方法返回值:調用valueGenerator的靜態方法getStaticValue,帶有兩個參數 --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="valueGenerator" /> <property name="targetMethod" value="getParamValue" /> <property name="arguments"> <!-- 使用list元素列出調用方法的多個參數,按形參的順序加載 --> <list> <value>address</value> <value>china</value> </list> </property> </bean> </property> </bean> <!-- 將方法返回值定義成Bean,該bean是反射調用java.lang.System的getProperties方法,而該方法的返回值類型是Properties 即該bean是一個Properties的類型的實例,至關於Properties sysProps = java.lang.System.getProperties(); --> <bean id="sysProps" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="java.lang.System" /> <property name="targetMethod" value="getProperties" /> </bean> <!-- 此bean至關於name = sysProps.getProperty("java.version"); --> <bean id="son8" class="com.pa.spring.test.inject.Son"> <property name="name"> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetObject" ref="sysProps" /> <!-- 因爲上述bean(sysProps)的類型是Properties,因此這裏調用的就是它的getProperties方法 --> <property name="targetMethod" value="getProperty" /> <property name="arguments"> <list> <value>java.version</value> </list> </property> </bean> </property> </bean> </beans>
測試類
package com.pa.spring.test.inject; import java.util.Properties; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test6 { public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("/com/pa/spring/test/inject/beans6.xml"); System.out.println("son1:age=" + context.getBean("son1", Son.class).getAge()); System.out.println("son2:age=" + context.getBean("son2", Son.class).getAge()); System.out.println("son3:age=" + context.getBean("son3", Son.class).getAge()); System.out.println("------------------------"); System.out.println("age1=" + context.getBean("age1")); System.out.println("age2=" + context.getBean("age2")); System.out.println("age3=" + context.getBean("age3")); System.out.println("------------------------"); System.out.println("son4:age=" + context.getBean("son4", Son.class).getAge()); System.out.println("son5:age=" + context.getBean("son5", Son.class).getAge()); System.out.println("son6:name=" + context.getBean("son6")); System.out.println("son7:name=" + context.getBean("son7", Son.class).getName()); System.out.println("son8:name=" + context.getBean("son8", Son.class).getName()); System.out.println("-----------測試son8的值和實際值-------------"); Properties prop = java.lang.System.getProperties(); String javaVersion = prop.getProperty("java.version"); System.out.println(javaVersion); } }
使用的是spring3.2版本,還要加上common-logging.jar,拷貝至java工程能夠直接運行
這裏主要涉及到下列3個類的注入方式:
PropertyPathFactoryBean
FieldRetrievingFactoryBean
MethodInvokingFactoryBean
在Spring配置文件中使用XML文件進行配置,其實是讓Spring執行了相應的代碼,例如:
使用<bean>元素,其實是讓Spring執行無參或有參構造器
使用<property>元素,其實是讓Spring執行一次setter方法
但Java程序還可能有其餘類型的語句:調用getter方法、調用普通方法、訪問類或對象的Field等,而Spring也爲這種語句提供了對應的配置語法:
調用getter方法:使用PropertyPathFactoryBean
調用類或對象的Filed值:使用FiledRetrievingFactoryBean
調用普通方法:使用MethodInvokingFactoryBean
PropertyPathFactoryBean:注入其餘Bean的屬性值
PropertyPathFactoryBean用來得到目標Bean的屬性值(實際上就是調用getter方法返回的值),得到的值能夠注入給其餘的Bean,也能夠直接定義新的Bean,以下:
<!-- 將一個類注入到另外一個類的屬性中,並 --> <bean id="person" class="com.pa.spring.test.inject.Person"> <property name="age" value="30" /> <property name="son"> <!-- 屬性son不是一個簡單值,而是Son類型,因此注入的時候就須要使用Son類型的Bean --> <bean class="com.pa.spring.test.inject.Son"> <property name="age" value="12" /> </bean> </property> </bean> <!-- 這個son的bean並不只是Son的實例,而是person bean的屬性 --> <bean id="son1" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"> <!-- 肯定目標Bean,代表son1來自哪一個Bean的組件 --> <property name="targetBeanName" value="person" /> <!-- 肯定屬性,代表son1來自目標Bean的哪一個屬性 --> <property name="propertyPath" value="son" /> </bean>
Bean實例的屬性值,不只能夠注入另外一個Bean,還可將Bean實例的屬性值直接定義成Bean實例,這也是經過PropertyPathFactoryBean完成的。對上面的配置文件增長這樣一段:
<bean id="son2" class="com.pa.spring.test.inject.Son"> <!-- age屬性不是直接注入,而是將person中的son的age屬性賦值給son2的age屬性 --> <property name="age"> <!-- 注意這裏使用的是PropertyPathFactoryBean --> <bean id="person.son.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean" /> </property> </bean>
FieldRetrievingFactoryBean:注入其餘Bean的Field值
經過FieldRetrievingFactoryBean類,能夠將其餘Bean的Field值注入給其餘Bean,或者直接定義新的Bean。下面是配置片斷:
<!-- 使用一個類的靜態屬性值注入到Son類的 age屬性中 --> <bean id="son3" class="com.pa.spring.test.inject.Son"> <property name="age"> <bean id="com.pa.spring.test.inject.InjectConstant.AAA" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" /> </property> </bean>