天天看點

Spring中的屬性注入

完整版見https://jadyer.github.io/

示範了int、String、數組、list、set、map、Date等屬性的注入

其中Date類型的注入則是借助了Spring提供的屬性編輯器來實作的

首先是用到的五個實體類

package com.jadyer.model;

import java.util.Date;

import java.util.List;

import java.util.Map;

import java.util.Set;

/**

* 常見屬性的注入

* @see 包括int,String,Array,list,set,map,Date的注入

*/

public class Bean11 {

private Integer intValue;

private String strValue;

private String[] arrayValue;

private List listValue;

private Set setValue;

private Map mapValue;

private Date dateValue;

/* 七個屬性的setter和getter略 */

}

package com.jadyer.model;

public class Bean22 {

private Bean33 bean33;

private Bean44 bean4422; //注入:與屬性名無關,與setBean44()有關

private Bean55 bean55;

/* 三個屬性的setter和getter略 */

}

package com.jadyer.model;

public class Bean33 {

private Integer id;

private String name;

private String sex;

/* 三個屬性的setter和getter略 */

}

package com.jadyer.model;

public class Bean44 {

private Integer id;

private String name;

private String sex;

private Integer age;

/* 四個屬性的setter和getter略 */

}

package com.jadyer.model;

public class Bean55 {

private String password;

/* 關于password的setter和getter略 */

}

然後是我們自定義的java.util.Date類型轉換器

package com.jadyer.util;

import java.beans.PropertyEditorSupport;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

/**

* java.util.Date屬性編輯器。相當于類型轉換器。這裡是将String轉為Date型

* @see ----------------------------------------------------------------------------------------

* @see 該示例主要讓大家知道Spring也有這種機制,不是讓大家以後寫屬性編輯器

* @see 需要寫屬性編輯器的幾率太少了,隻要知道Spring也有類似的機制就可以了

* @see ----------------------------------------------------------------------------------------

* @see 所謂的屬性編輯器,就是将Spring配置檔案中的字元串轉換成相應的Java對象

* @see Spring内置了一些屬性編輯器,也可以自定義屬性編輯器

* @see 自定義屬性編輯器事,須繼承PropertyEditorSupport類并覆寫setAsText()方法

* @see 最後再将自定義的屬性編輯器注入到Spring中,即可

* @see ----------------------------------------------------------------------------------------

*/

public class UtilDatePropertyEditor extends PropertyEditorSupport {

private String pattern; //将轉換的格式放到配置檔案中,讓Spring注入進來

public void setPattern(String pattern) {

this.pattern = pattern;

}

@Override

public void setAsText(String text) throws IllegalArgumentException {

System.out.println("======UtilDatePropertyEditor.setAsText()======" + text);

try {

Date date = new SimpleDateFormat(pattern).parse(text);

this.setValue(date); //注意:這裡放進去的是一個java.util.Date對象,故輸出的時間是預設的格式

} catch (ParseException e) {

e.printStackTrace();

throw new IllegalArgumentException(text); //繼續向上抛參數非法的異常

}

}

}

用到的針對所有實體類的applicationContext-beans.xml檔案

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"

default-lazy-init="true">

<!-- default-lazy-init="true"屬性的說明,詳見InjectionTest.java類的第49行 -->

<!-- default-autowire="byName或byType",這是Spri0ng提供的自動裝配bean的兩種方式byName和byType,詳解略 -->

<!-- ***********************【LAZY====延遲初始化】*********************************************************************** -->

<!-- 執行testInjection22()時預設的會輸出======UtilDatePropertyEditor.setAsText()======2010年06月04日 -->

<!-- 即此時并未設定default-lazy-init="true",這說明Bean11中的dateValue屬性的值被注入了 -->

<!-- 事實上,預設的Spring在建立ApplicationContext時,會将配置檔案中所有的對象執行個體化并進行注入 -->

<!-- 這樣做的好處是如果Spring配置檔案中的某些配置寫錯了,它立刻就能檢測出來 -->

<!-- 而Struts1.X的配置檔案,如果某個類寫錯了,是不會出問題的,隻有在真正執行的時候,才會出問題 -->

<!-- 對于Spring而言,也可以采用相關的屬性延遲配置檔案的初始化,即default-lazy-init="true" -->

<!-- 即隻有真正使用的時候,再去New這個對象,再為屬性注入。這時就涉及到LAZY,即延遲初始化 -->

<!-- 隻需修改Spring配置檔案即可,如<beans xsi:schemaLocation="http://www...." default-lazy-init="true"> -->

<!-- 這時的作用範圍即整個配置檔案,同理也可對各個<bean>标簽的lazy-init屬性進行單獨配置 -->

<!-- 但一般都不會這麼設定,而是在BeanFactory建立的時候,即完成注入,這樣也便于檢查出錯誤 -->

<!-- ***************************************************************************************************************** -->

<bean id="bean11" class="com.jadyer.model.Bean11">

<property name="intValue" value="123"/><!-- 注入時,字元串123會自動轉換為int型 -->

<property name="strValue" value="Hello_Spring"/>

<property name="arrayValue">

<list>

<value>array11</value>

<value>array22</value>

</list>

</property>

<property name="listValue">

<list>

<value>list11</value>

<value>list22</value>

</list>

</property>

<property name="setValue">

<set>

<value>set11</value>

<value>set22</value>

</set>

</property>

<property name="mapValue">

<map>

<entry key="key11" value="value11"/>

<entry key="key22" value="value22"/>

</map>

</property>

<property name="dateValue" value="2010年06月04日"/><!-- 這裡Date格式應與applicationContext-editor.xml配置的相同 -->

</bean>

<bean id="bean22" class="com.jadyer.model.Bean22">

<property name="bean33" ref="bean33"/>

<property name="bean44" ref="bean44"/>

<property name="bean55" ref="bean55"/>

</bean>

<bean id="bean55" class="com.jadyer.model.Bean55">

<property name="password" value="123"/>

</bean>

</beans>

用到的針對公共實體類的applicationContext-common.xml檔案

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<!-- 利用抽象bean提取出公共配置 -->

<!-- 首先指定<bean>标簽的abstract屬性為true,然後在其它<bean>中指定其parent即可 -->

<bean id="AbstractBean" abstract="true">

<property name="id" value="2"/>

<property name="name" value="張起靈"/>

<property name="sex" value="男"/>

</bean>

<bean id="bean33" class="com.jadyer.model.Bean33" parent="AbstractBean"/>

<bean id="bean44" class="com.jadyer.model.Bean44" parent="AbstractBean">

<property name="age" value="26"/>

</bean>

</beans>

<!-- 使用AbstractBean之前的bean33和bean44的原形如下 -->

<!--

<bean id="bean33" class="com.jadyer.model.Bean33">

<property name="id" value="100"/>

<property name="name" value="張三"/>

<property name="sex" value="男"/>

</bean>

<bean id="bean44" class="com.jadyer.model.Bean44">

<property name="id" value="100"/>

<property name="name" value="張三"/>

<property name="sex" value="男"/>

<property name="age" value="90"/>

</bean>

-->

用到的針對java.util.Date屬性編輯器的applicationContext-editor.xml檔案

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean id="utilDatePropertyEditor" class="com.jadyer.util.UtilDatePropertyEditor">

<property name="pattern" value="yyyy年MM月dd日"/>

</bean>

<!-- 檢視源碼得知,在CustomEditorConfigurer類的131行提供了一個setCustomEditors方法,是以就能夠注入了 -->

<bean id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors">

<map>

<entry key="java.util.Date" value-ref="utilDatePropertyEditor"/>

</map>

</property>

</bean>

</beans>

<!-- 也可以使用内部<bean>把utilDatePropertyEditor寫在内部 -->

<!-- 這樣就隻有它自己有權使用了,外部就無法使用了 -->

<!-- 由于不提供外界通路,是以内部<bean>沒有id屬性 -->

<!-- 示例如下 -->

<!--

<bean id="customEditors" class="org.springframework.beans.factory.config.CustomEditorConfigurer">

<property name="customEditors">

<map>

<entry key="java.util.Date">

<bean class="com.jadyer.util.UtilDatePropertyEditor">

<property name="pattern" value="yyyy年MM月dd日"/>

</bean>

</entry>

</map>

</property>

</bean>

-->

最後是使用JUnit3.8寫的單元測試類

package com.jadyer.junit;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jadyer.model.Bean11;

import com.jadyer.model.Bean22;

public class PropertyInjectionTest extends TestCase {

private ApplicationContext factory;

@Override

protected void setUp() throws Exception {

/****====讀取單一的配置檔案====****/

//factory = new ClassPathXmlApplicationContext("applicationContext.xml");

/****====利用數組讀取多個配置檔案====****/

//這樣就會把兩個配置檔案作為一個來使用,表面上看是作為兩個使用的

//其實内部是作為一個使用的,是以在多個配置檔案中,裡面的id不能重複

//但是name屬性可以重複,就好像人的身份證編号和名字的差別是一樣的

//String[] configLocations = new String[]{"applicationContext.xml", "applicationContext-editor.xml"};

//factory = new ClassPathXmlApplicationContext(configLocations);

/****=====利用 * 比對模式讀取多個配置檔案====****/

//業界流行的一句話:約定優于配置

//是以說當有了一個統一的比較好的約定之後,就可以利用架構提供的功能,減少配置量

//另外:如果沒有讀取到applicationContext-*.xml,此時即便存在applicationContext.xml,它也不會讀的

factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");

}

/**

* 該方法示範的是常見屬性的注入,包括int,String,Array,list,set,map,Date的注入

* @see 其中Date類型的注入則是借助了Spring屬性編輯器來實作的

*/

public void testInjection11() {

//Bean11 bean11 = new Bean11(); //若簡單的new,那麼它的屬性是不會被注入的。注入的前提必須是從IoC容器中拿出來的,才會注入

Bean11 bean11 = (Bean11)factory.getBean("bean11"); //此時bean11就是從IoC容器中擷取到的,是以它的依賴就會被全部注入

System.out.println("bean11.intValue=" + bean11.getIntValue());

System.out.println("bean11.strValue=" + bean11.getStrValue());

System.out.println("bean11.arrayValue=" + bean11.getArrayValue());

System.out.println("bean11.listValue=" + bean11.getListValue());

System.out.println("bean11.setValue=" + bean11.getSetValue());

System.out.println("bean11.mapValue=" + bean11.getMapValue());

System.out.println("bean11.dateValue=" + bean11.getDateValue());

}

/**

* 該方法主要示範的是将公共的配置進行抽象,以減少配置量

*/

public void testInjection22() {

Bean22 bean22 = (Bean22)factory.getBean("bean22");

System.out.println("bean22.bean33.id=" + bean22.getBean33().getId());

System.out.println("bean22.bean33.name=" + bean22.getBean33().getName());

System.out.println("bean22.bean33.sex=" + bean22.getBean33().getSex());

System.out.println("bean22.bean44.id=" + bean22.getBean44().getId());

System.out.println("bean22.bean44.name=" + bean22.getBean44().getName());

System.out.println("bean22.bean44.sex=" + bean22.getBean44().getSex());

System.out.println("bean22.bean44.age=" + bean22.getBean44().getAge());

System.out.println("bean22.bean55.password=" + bean22.getBean55().getPassword());

}

}