Spring很是見注入

以前工做時,公司封裝的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>
相關文章
相關標籤/搜索