原始方式:spring四種依賴注入方式 java
spring有多種依賴注入的形式,下面僅介紹spring經過xml進行IOC配置的方式:spring
Set注入less
這是最簡單的注入方式,假設有一個SpringAction,類中須要實例化一個SpringDao對象,那麼就能夠定義一個private的SpringDao成員變量,而後建立SpringDao的set方法(這是ioc的注入入口):ssh
package com.bless.springdemo.action; public class SpringAction { //注入對象springDao private SpringDao springDao; //必定要寫被注入對象的set方法 public void setSpringDao(SpringDao springDao) { this.springDao = springDao; } public void ok(){ springDao.ok(); } }
隨後編寫spring的xml文件,<bean>中的name屬性是class屬性的一個別名,class屬性指類的全名,由於在SpringAction中有一個公共屬性Springdao,因此要在<bean>標籤中建立一個<property>標籤指定SpringDao。<property>標籤中的name就是SpringAction類中的SpringDao屬性名,ref指下面<bean name="springDao"...>,這樣實際上是spring將SpringDaoImpl對象實例化而且調用SpringAction的setSpringDao方法將SpringDao注入:函數
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(1)依賴注入,配置當前類中相應的屬性--> <property name="springDao" ref="springDao"></property> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
構造器注入測試
這種方式的注入是指帶有參數的構造函數注入,看下面的例子,我建立了兩個成員變量SpringDao和User,可是並未設置對象的set方法,因此就不能支持第一種注入方式,這裏的注入方式是在SpringAction的構造函數中注入,也就是說在建立SpringAction對象時要將SpringDao和User兩個參數值傳進來:ui
public class SpringAction { //注入對象springDao private SpringDao springDao; private User user; public SpringAction(SpringDao springDao,User user){ this.springDao = springDao; this.user = user; System.out.println("構造方法調用springDao和user"); } public void save(){ user.setName("卡卡"); springDao.save(user); } }
在XML文件中一樣不用<property>的形式,而是使用<constructor-arg>標籤,ref屬性一樣指向其它<bean>標籤的name屬性:this
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(2)建立構造器注入,若是主類有帶參的構造方法則需添加此配置--> <constructor-arg ref="springDao"></constructor-arg> <constructor-arg ref="user"></constructor-arg> </bean> <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean> <bean name="user" class="com.bless.springdemo.vo.User"></bean>
解決構造方法參數的不肯定性,你可能會遇到構造方法傳入的兩參數都是同類型的,爲了分清哪一個該賦對應值,則須要進行一些小處理:spa
下面是設置index,就是參數位置:prototype
<bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <constructor-arg index="0" ref="springDao"></constructor-arg> <constructor-arg index="1" ref="user"></constructor-arg> </bean>
另外一種是設置參數類型:
<constructor-arg type="java.lang.String" ref=""/>
靜態工廠的方法注入
靜態工廠顧名思義,就是經過調用靜態工廠的方法來獲取本身須要的對象,爲了讓spring管理全部對象,咱們不能直接經過"工程類.靜態方法()"來獲取對象,而是依然經過spring注入的形式獲取:
package com.bless.springdemo.factory; import com.bless.springdemo.dao.FactoryDao; import com.bless.springdemo.dao.impl.FactoryDaoImpl; import com.bless.springdemo.dao.impl.StaticFacotryDaoImpl; public class DaoFactory { //靜態工廠 public static final FactoryDao getStaticFactoryDaoImpl(){ return new StaticFacotryDaoImpl(); } }
一樣看關鍵類,這裏我須要注入一個FactoryDao對象,這裏看起來跟第一種注入如出一轍,可是看隨後的xml會發現有很大差異:
public class SpringAction { //注入對象 private FactoryDao staticFactoryDao; public void staticFactoryOk(){ staticFactoryDao.saveFactory(); } //注入對象的set方法 public void setStaticFactoryDao(FactoryDao staticFactoryDao) { this.staticFactoryDao = staticFactoryDao; } }
Spring的IOC配置文件,注意看<bean name="staticFactoryDao">指向的class並非FactoryDao的實現類,而是指向靜態工廠DaoFactory,而且配置 factory-method="getStaticFactoryDaoImpl"指定調用哪一個工廠方法:
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction" > <!--(3)使用靜態工廠的方法注入對象,對應下面的配置文件(3)--> <property name="staticFactoryDao" ref="staticFactoryDao"></property> </property> </bean> <!--(3)此處獲取對象的方式是從工廠類中獲取靜態方法--> <bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" factory-method="getStaticFactoryDaoImpl"></bean>
實例工廠的方法注入
實例工廠的意思是獲取對象實例的方法不是靜態的,因此你須要首先new工廠類,再調用普通的實例方法:
public class DaoFactory { //實例工廠 public FactoryDao getFactoryDaoImpl(){ return new FactoryDaoImpl(); } }
那麼下面這個類沒什麼說的,跟前面也很類似,可是咱們須要經過實例工廠類建立FactoryDao對象:
public class SpringAction { //注入對象 private FactoryDao factoryDao; public void factoryOk(){ factoryDao.saveFactory(); } public void setFactoryDao(FactoryDao factoryDao) { this.factoryDao = factoryDao; } }
最後看spring配置文件:
<!--配置bean,配置後該類由spring管理--> <bean name="springAction" class="com.bless.springdemo.action.SpringAction"> <!--(4)使用實例工廠的方法注入對象,對應下面的配置文件(4)--> <property name="factoryDao" ref="factoryDao"></property> </bean> <!--(4)此處獲取對象的方式是從工廠類中獲取實例方法--> <bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean> <bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
總結
Spring IOC注入方式用得最多的是(1)(2)種,多謝多練就會很是熟練。
另外注意:經過Spring建立的對象默認是單例的,若是須要建立多實例對象能夠在<bean>標籤後面添加一個屬性:
<bean name="..." class="..." scope="prototype">
註解方式:Spring零配置經過註解實現Bean依賴注入
Spring3的基於註解實現Bean依賴注入支持以下三種註解:
Spring自帶依賴注入註解: Spring自帶的一套依賴注入註解;
JSR-250註解:Java平臺的公共註解,是Java EE 5規範之一,在JDK6中默認包含這些註解,從Spring2.5開始支持。
JSR-330註解:Java 依賴注入標準,Java EE 6規範之一,可能在加入到將來JDK版本,從Spring3開始支持;
JPA註解:用於注入持久化上下文和屍體管理器。
這三種類型的註解在Spring3中都支持,相似於註解事務支持,想要使用這些註解須要在Spring容器中開啓註解驅動支持,即便用以下配置方式開啓:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> </beans>
1、@Required:依賴檢查;
對應於基於XML配置中的依賴檢查,但XML配置的依賴檢查將檢查全部setter方法,詳見【3.3.4 依賴檢查】;
基於@Required的依賴檢查表示註解的setter方法必須,即必須經過在XML配置中配置setter注入,若是沒有配置在容器啓動時會拋出異常從而保證在運行時不會遇到空指針異常,@Required只能放置在setter方法上,且經過XML配置的setter注入,可使用以下方式來指定:
Java代碼
@Requried setter方法
一、準備測試Bean
package cn.javass.spring.chapter12; public class TestBean { private String message; @Required public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean" class="cn.javass.spring.chapter12.TestBean"> <property name="message" ref="message"/> </bean> <bean id="message" class="java.lang.String"> <constructor-arg index="0" value="hello"/> </bean>
三、測試類和測試方法以下:
package cn.javass.spring.chapter12; //省略import public class DependencyInjectWithAnnotationTest { private static String configLocation = "classpath:chapter12/dependecyInjectWithAnnotation.xml"; private static ApplicationContext ctx = new ClassPathXmlApplicationContext("configLocation"); //一、Spring自帶依賴注入註解 @Test public void testRequiredForXmlSetterInject() { TestBean testBean = ctx.getBean("testBean", TestBean.class); Assert.assertEquals("hello", testBean.getMessage()); } }
在XML配置文件中必須指定setter注入,不然在Spring容器啓動時將拋出以下異常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testBean' defined in class path resource [chapter12/dependecyInjectWithAnnotation.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'message' is required for bean 'testBean'
2、@Autowired:自動裝配
自動裝配,用於替代基於XML配置的自動裝配,詳見【3.3.3 自動裝配】。
基於@Autowired的自動裝配,默認是根據類型注入,能夠用於構造器、字段、方法注入,使用方式以下:
@Autowired(required=true) 構造器、字段、方法
@Autowired默認是根據參數類型進行自動裝配,且必須有一個Bean候選者注入,若是容許出現0個Bean候選者須要設置屬性「required=false」,「required」屬性含義和@Required同樣,只是@Required只適用於基於XML配置的setter注入方式。
(1)、構造器注入:經過將@Autowired註解放在構造器上來完成構造器注入,默認構造器參數經過類型自動裝配,以下所示:
一、準備測試Bean,在構造器上添加@AutoWired註解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean11 { private String message; @Autowired //構造器注入 private TestBean11(String message) { this.message = message; } //省略message的getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean11"class="cn.javass.spring.chapter12.TestBean11"/>
三、測試類以下:
@Test public void testAutowiredForConstructor() { TestBean11 testBean11 = ctx.getBean("testBean11", TestBean11.class); Assert.assertEquals("hello", testBean11.getMessage()); }
在Spring配置文件中沒有對「testBean11」進行構造器注入和setter注入配置,而是經過在構造器上添加@ Autowired來完成根據參數類型完成構造器注入。
(2)、字段注入:經過將@Autowired註解放在構造器上來完成字段注入。
一、準備測試Bean,在字段上添加@AutoWired註解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean12 { @Autowired //字段注入 private String message; //省略getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean12" class="cn.javass.spring.chapter12.TestBean12"/>
三、測試方法以下:
@Test public void testAutowiredForField() { TestBean12 testBean12 = ctx.getBean("testBean12", TestBean12.class); Assert.assertEquals("hello", testBean12.getMessage()); }
字段注入在基於XML配置中無相應概念,字段注入不支持靜態類型字段的注入。
(3)、方法參數注入:經過將@Autowired註解放在方法上來完成方法參數注入。
一、準備測試Bean,在方法上添加@AutoWired註解:
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; public class TestBean13 { private String message; @Autowired //setter方法注入 public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
package cn.javass.spring.chapter12; //省略import public class TestBean14 { private String message; private List<String> list; @Autowired(required = true) //任意一個或多個參數方法注入 private void initMessage(String message, ArrayList<String> list) { this.message = message; this.list = list; } //省略getter和setter }
二、在Spring配置文件(chapter12/dependecyInjectWithAnnotation.xml)添加以下Bean配置:
<bean id="testBean13" class="cn.javass.spring.chapter12.TestBean13"/> <bean id="testBean14" class="cn.javass.spring.chapter12.TestBean14"/> <bean id="list" class="java.util.ArrayList"> <constructor-arg index="0"> <list> <ref bean="message"/> <ref bean="message"/> </list> </constructor-arg> </bean>
三、測試方法以下:
@Test public void testAutowiredForMethod() { TestBean13 testBean13 = ctx.getBean("testBean13", TestBean13.class); Assert.assertEquals("hello", testBean13.getMessage()); TestBean14 testBean14 = ctx.getBean("testBean14", TestBean14.class); Assert.assertEquals("hello", testBean14.getMessage()); Assert.assertEquals(ctx.getBean("list", List.class), testBean14.getList()); }
方法參數注入除了支持setter方法注入,還支持1個或多個參數的普通方法注入,在基於XML配置中不支持1個或多個參數的普通方法注入,方法注入不支持靜態類型方法的注入。
注意「initMessage(String message, ArrayList<String> list)」方法簽名中爲何使用ArrayList而不是List呢?具體參考【3.3.3 自動裝配】一節中的集合類型注入區別。
產考文檔:http://blessht.iteye.com/blog/1162131
http://www.iteye.com/topic/1121784