1. 程式人生 > >深入理解Spring核心技術---Spring中的依賴注入

深入理解Spring核心技術---Spring中的依賴注入

         在前面的幾篇部落格中給大家介紹了Spring中的IOC容器,現在大家應該都知道IOC容器的概念和實現的原理了吧,IOC容器是Spring的核心,他的功能就是幫助開發者去儲存物件以及管理物件之間的關係。不用讓開發者自己去管理物件之間的關係,使開發者只需要專注於業務邏輯。前面的一篇部落格中給大家手動實現了一個IOC容器,通過反射載入配置檔案建立並把物件儲存在一個Map集合中,這裡的Map集合就是一個IOC容器。好了,既然已經知道了那麼Spring中是怎麼建立並存儲物件的原理。那麼今天就來聊一聊Spring中是如何處理物件之間的關係。

          首先大家應該知道什麼是物件之間的關係吧,物件與物件之間的關係用專業的術語叫做依賴,故名思意,也就是說當一個物件在實現某個功能的時候需要使用另外一個物件的屬性或者方法的時候,我們就說這兩個物件之間具有依賴關係。

   好了,大家可能會好奇,假設在Spring容器中有兩個物件A和B,物件A在實現他的功能的時候需要使用物件B的一個屬性,那麼我們就稱之為物件A依賴與物件B。大家首先可能會想到裝飾者模式。將B物件的屬性直接通過構造直接傳入即可。那麼在Spring中我們該怎麼在配置檔案中配置Bean呢?

         其實在Spring中我們並不需要去關注這個問題,前面說了Spring容器會幫我們管理物件之間的關係,所以我們直接用A物件就可以了,不用去處理A物件和B物件之間的關係。原因就是在Spring建立A物件的時候就會自動的把A物件所依賴的B物件注入到B物件中,而這個過程就是我們今天要聊的話題------DI(Dependency Injection)即依賴注入。

         概念性的東西解釋的差不多了,下面來通過一個案例來解釋一下把,開啟eclipse,建立一個工程,包結構如下圖所示:

接著我們先來建立 dao層的 介面,程式碼如下:

public interface DIDemo {
	public void diDemo();
}

接著建立該介面的實現類,程式碼如下:

public class DIDemoImpl implements DIDemo {

	@Override
	public void diDemo() {
		// TODO Auto-generated method stub
		System.out.println("Spring 中的 Dao");
	}

}

為了方便演示效果,這裡我們只些簡單的一條列印語句。好了,dao層的工作做完了之後我們就來開始編寫service層的程式碼了。

先來定義service層的介面程式碼如下:


public interface DIDemoService {
	public void diDemoService();
}

同樣的介面中只有一個方法,接下倆看看該介面的實現類把,程式碼如下:

import di.dao.DIDemo;

public class DIDemoServiceImpl implements DIDemoService {
	
	//宣告一個dao的物件
	private DIDemo dao;
	//新增該物件的set方法,用於依賴注入
	

	public void setDao(DIDemo dao) {
		this.dao = dao;
	}


	@Override
	public void diDemoService() {
		this.dao.diDemo();
		// TODO Auto-generated method stub
		System.out.println("Spring 中的 Service ");
	}

}

大家可以看到,在上面的一段程式碼中我特意的讓dao層的物件和service層產生依賴關係。該類種是通過set方法將dao物件注入到service層的物件中。好了到了這裡我們就來編寫配置檔案了。

bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       					   http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<!-- dao -->
	<bean id="dao" class="di.dao.DIDemoImpl"></bean>
	<!-- service -->
	<bean id="DIService" class="di.service.DIDemoServiceImpl">
		<!-- 注入dao物件 -->
		<property name="dao" ref="dao"/>
	</bean>
	
	</beans>

大家可以看到,在service的配置中有一段使用了<property>,該標籤的功能就是在id標識的物件中注入其他物件,我們可以看到該標籤中有兩個屬性值,一個是name,另外一個是name對應的值。name對應的值有兩種情況,一個是value,一個是ref。value對應的是給屬性賦值是基本資料型別和string型別的。ref是對應的當前xml檔案中配置過的bean型別。本例中由於 dao是在上一行配置過,所以選擇ref。

好了,配置的工作已經做完了,下面就來編寫測試類了。測試類的程式碼如下 :

public class Client {
	@Test
	public void  diTest() {
		
		((DIDemoService)(new ClassPathXmlApplicationContext("bean.xml")
				.getBean("DIService"))).diDemoService();
	}
}

好了,上面的就是測試類的程式碼了,大家可以看到這個類中只有一句程式碼。大家先來看看結果,稍後再給大家解釋。

大家可以看到,測試的結果是同時打印出了dao物件中的一句話,這段程式碼可能不好理解,大家可以看到getBean方法中傳入的是Service層的物件,但是打印出來了dao層的物件中的一句話,這就是spring中的依賴注入。這段程式碼可能大家看不懂,大家再來看下面只能這段程式碼,或許就豁然開朗了。

@Test
	public void  diTest() {
		ApplicationContext application = new ClassPathXmlApplicationContext("bean.xml");
		DIDemoService service = (DIDemoService)application.getBean("DIService");
		service.diDemoService();
	}
	

大家可以看到,上述方法中有三行程式碼,第一行使用來載入配置檔案的,第二行是用來獲取我們需要用的service層的物件的,第三行是執行service物件的方法。這個相信大家都能看明白。那麼為什麼我會先給大家看上面的那種寫法呢?這裡我主要是想給大家介紹一下記憶體相關的知識點。大家都知道,當new出現的時候就會在堆記憶體上分配一塊空間,用來存放new出來的物件,每個new出來的物件都會有一個地址,該地址用一個16進位制的數來標識,而物件的引用就比如application的值就是物件的地址,這個時候我們稱之為application這個引用指向了new ClassPathXmlApplicationContext("bean.xml");這個物件。由於本案例中主要就是演示效果,所以寫成一句程式碼不用去宣告兩個物件的引用,這個時候就可以節省兩塊棧記憶體的空間。和實際物件不同,物件的引用application是存放在棧記憶體中的。這個還真有點不好解釋,反正大家只需要知道,在開發的過程中如果考慮效能的話究竟可能的減少棧記憶體的使用。關於記憶體的問題後面會專門給大家介紹。

好了,今天主要給大家演示了一下spring中的依賴注入,本案例中使用的是set方法注入,其實在Spring 中不光有這一種注入的方式,也有通過構造方法的方式注入,原理是使用帶引數的構造方法注入依賴的物件,類似於裝飾者模式。

需要注意的是Spring中不支援介面的注入方式。好了,今天就和給大家介紹到這裡了,希望大家都能有自己的收穫。下一篇部落格中講給大家詳細的講解Spring中的AOP。