Spring的依賴注入對調用者和被調用者幾乎沒有任何要求,完全支持對POJO之間依賴關係的管理。有以下幾種注入方式:
因爲對於javaBean來說,我們可以通過setter和getter方法分別改變對象和獲取對象的屬性。所以當前對象只要爲其依賴對象所對應的屬性添加setter方法,就可以通過setter方法將相應的依賴對象設置到被注入對象中。例如下面的代碼:
package com.tgb.depency;
/**
* 定義Person接口
* @author MINGXUANYUN
*
*/
public interface Person {
//定義一個吃東西的方法
public void eatSomething();
//定義一個個人信息方法
public String personInfo();
}
.Eat接口
package com.tgb.depency;
public interface Eat {
//定義一個吃蘋果的方法
public String eatApple();
}
.Person的實現類
/**
* Person的實現類
* @author MINGXUANYUN
*/
public class Huohuo implements Person{
private Eat eat;
//默認的構造器
public Huohuo(){}
public Eat getEat() {
return eat;
}
public void setEat(Eat eat) {
this.eat = eat;
}
//實現Person吃東西的方法
@Override
public void eatSomething() {
System.out.println(eat.eatApple());
}
@Override
public String personInfo() {
return null;
}
}
.Eat的實現類
/**
* 大口大口吃
* @author MINGXUANYUN
*/
public class WideMouthEat implements Eat {
@Override
public String eatApple() {
return"張大嘴巴吃蘋果很粗魯的!!!";
}
}
.配置文件,將Person實例和Eat實例組織在一起
<!--Setter注入測試實例 -->
<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
<property name="eat" ref="WideMouthEat"></property>
</bean>
<bean id="WideMouthEat" class="com.tgb.depencyimpl.WideMouthEat">
</bean>
從以上例子可以看出:Spring將bean與bean之間的依賴關係放到配置文件裏管理,而不是寫在代碼裏。通過配置文件,Spring精確的爲每個bean注入每個屬性。<bean>中的name屬性是class屬性的一個別名,class屬性指真正的實現類(類的全名)。Spring自動接管每個bean裏的 property元素定義。Spring再執行無參數的構造器,創建默認的bean後,調用對應的setter方法爲程序注入屬性值。
.主程序
public class SetterTest {
public static void main(String[] args) {
//實例化Spring的上下文
ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
//強制轉換接口類型
Person person = (Person) ctx.getBean("Huohuo");
//執行Person的eatSomething方法
person.eatSomething();
}
}
.運行結果輸出 :
張大嘴巴吃蘋果很粗魯的!!!
說明: 主程序調用person.eatSomething方法,該方法方法體裏需要有Eat的實例,但主程序裏並沒有任何地方爲Person實例傳入Eat實例,Eat實例是由Spring在運行期間動態注入的。Person實例不需要了解Eat實例的具體實現和創建過程。程序運行到Eat實例的時候,Spring自動創建Eat實例,然後注入給它的調用者,Person實例運行到需要Eat實例的時候,自動產生Eat實例。
這樣有什麼好處呢?如果我們需要另一個Eat實現類來爲Person類使用。Person和其實現類都無需改變。只需要增加一個Eat的實現類,並在配置文件中配置就可以。
例如,增加Eat實現類ChewslowlyEat
import com.tgb.depency.Eat;
public class ChewslowlyEat implements Eat {
@Override
public String eatApple() {
return "細嚼慢嚥淑女的典範!!";
}
}
修改配置文件:
<bean id="Huohuo" class= "com.tgb.depencyimpl.Huohuo">
<property name="eat" ref="ChewslowlyEat"></property>
</bean>
<bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"></bean>
輸出結果:
細嚼慢嚥淑女的典範!!
2. 構造器注入
指被注入對象通過在其構造函數中聲明依賴對象的參數列表。
.定義一個Person實現類,用於構造器注入
/**
* 構造器注入測試
* @author MINGXUANYUN
*/
public class Yunyun implements Person{
private String userName;
private String kind;
private Eat eat;
//默認構造方法
public Yunyun(){};
//構造注入所需的帶參數構造器
public Yunyun(Eat eat,String userName,String kind){
this.eat = eat;
this.userName = userName;
this.kind = kind;
}
@Override
public String personInfo() {
return userName + "永遠" + kind +"歲" + "----" + eat.eatApple();
}
@Override
public void eatSomething() {
// TODO Auto-generated method stub
}
}
在構造Yunyun實例時,創建三個成員變量userName、kind和對象類型的eat。但是並沒有設置setter方法。在構造Person實例時,Spring爲Person實例注入所依賴的Eat實例並且爲兩個成員變量賦值。構造注入的配置文件如下:
.xml配置文件
<!--構造器注入配置實例 -->
<bean id="Yunyun" class= "com.tgb.depencyimpl.Yunyun">
<constructor-arg index="0" ref="ChewslowlyEat"></constructor-arg>
<constructor-arg index="1">
<value>朱火雲 </value>
</constructor-arg>
<constructor-arg index="2">
<value>18</value>
</constructor-arg>
</bean>
<bean id="ChewslowlyEat" class="com.tgb.depencyimpl.ChewslowlyEat"/>
在配置文件中,不用<property>的形式,而是使用<constructor-arg>標籤。ref屬性指向其它<bean>標籤的name屬性。由於我們可能傳入多個類型一致的構造參數。所以可以用type和index確定我們使用的哪一個構造函數。
.主程序
public class ConstructorTest {
public static void main(String[] args) {
String fileName = "bean.xml";
ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);
// 取得一個實例
Yunyun yunyun = (Yunyun) ac.getBean("Yunyun");
System.out.println(yunyun.personInfo());
}
}
輸出結果:
朱火雲 永遠18歲細嚼慢嚥淑女的典範!!
指通過調用靜態工廠的方法來獲取自己需要的對象。
.定義一個UserDao類
public class UserDao {
public static UserDao getInstance(){
return new UserDao("static factory method");
}
private String name="";
public UserDao(String name){
this.name = name;
}
public void create(){
System.out.println("create user from-" + name);
}
}
.定義一個UserManager類
import com.tgb.depency.UserDao;
public class UserManager {
//注入UserDao對象
private UserDao userDao;
public void createUser(){
userDao.create();
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
}
.xml配置文件
<!-- 靜態工廠方法注入 -->
<bean name="userManager" class="com.tgb.depencyimpl.UserManager">
<property name="userDao" ref="userDao"></property>
</bean>
<bean name="userDao" class="com.tgb.depency.UserDao" factory-method="getInstance">
</bean>
factory-menthod定義了userDao 。Bean使用UserDao類的getInstance方法來創建自己的實例。
.主程序
public class StaticFactoryTest {
public static void main(String[] args) {
String fileName = "bean.xml";
ApplicationContext ac = new FileSystemXmlApplicationContext(fileName);
UserManager userManager = (UserManager) ac.getBean("userManager");
userManager.createUser();
}
}
輸出結果:
create user from-static factory method
總結:我們原來學三層的時候,UI層調用BLL、BLL調用DAO層。各層與各層之間雖然抽象出了接口層,調用接口。但是在new的時候指向的還是具體的實現。而現在Spring有效的管理各層之間對象的調用。 不管是Action調用Services對象,還是Services調用Dao對象,Spring以鬆耦合的方式將它們組織在一起。各層之間不需要關心對象間的具體實現,以及如何創建,完全面向接口編程。