spring第二個特性是依賴註入。 學習依賴註入,首先應該明白兩個問題:1,誰依賴誰;2,誰註入,註入什麼?
spring第二個特性是依賴註入。
學習依賴註入,首先應該明白兩個問題:1,誰依賴誰;2,誰註入,註入什麼?
首先還是看代碼:
還是這個bean:
package testSpring.business.bean; import org.springframework.stereotype.Repository; import testSpring.business.iface.IPrint; /** * UserBean : * @author xuejupo [email protected] * create in 2016-2-16 上午9:22:39 */ public class UserBean implements IPrint{ @Override public String printObject() { // TODO Auto-generated method stub System.out.println("列印對象UserBean:"); return "abc"; } }
然後,我的業務邏輯需要在這個bean里使用上邊那個bean:
package testSpring.business.impl; import testSpring.business.iface.IPrint; /** * Print : * @author xuejupo [email protected] * create in 2016-2-16 上午10:23:37 */ public class Print { //需要列印的bean,註入的入口(需要註入的對象) private IPrint printBean; private String name; public void print(){ System.out.println("註入的name:"+name); this.printBean.printObject(); } /** * setPrintBean: set方法,set註入必備方法 * @param printBean * void 返回類型 */ public void setPrintBean(IPrint printBean){ this.printBean = printBean; } /** * setName: set方法,set註入必備方法 * @param name * void 返回類型 */ public void setName(String name){ this.name = name; } }
普通的使用print類的客戶端代碼:
Print p = new Print(); p.setPrintBean(new UserBean()); print.print();
也是挺簡單的代碼,但是,客戶端代碼就和具體的類print和userbean的代碼強耦合在一塊了,不符合開閉原則,所以就需要利用依賴註入往客戶端代碼中註入Pring對象,往Print類中註入Userbean對象。
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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <context:annotation-config/> <!-- 註冊javabean --> <bean id="userBean" class="testSpring.business.bean.MyBean" /> <!-- 註冊javabean --> <bean id="printBean" class="testSpring.business.impl.Print" > <!-- 註入javabean中的參數 --> <property name = "printBean" ref = "userBean"></property> <property name = "name" value = "haha"></property> </bean> </beans>
客戶端代碼:
//讀取配置文件(將配置文件中的bean載入進記憶體) ApplicationContext ctx = new ClassPathXmlApplicationContext("/testSpring/resources/applicationContext.xml"); //獲取的實例 Print bean=(Print)ctx.getBean("printBean"); //調用方法 bean.print();
列印結果:
註入的name:haha
列印對象MyBean:
可以看到,利用xml的配置信息,在客戶端代碼中不用具體new任何的java對象了,java對象的創建工作,和對象中元素的賦值工作可以交給xml(spring)處理。
回答文中開頭兩個問題:1.客戶端代碼中,具體對象的創建依賴於xml文件(spring,即IOC容器);2.是IOC容器註入,在運行期,根據xml的配置信息,將具體的對象註入到相應的bean中。
說一下自己理解中的IOC容器: 網上搜過,沒有什麼讓我滿意的回答,只能自己理解一下。我理解的IOC容器,其實就是web服務啟動後,tomcat(或其他的web伺服器)載入applicationContext.xml(註冊bean的spring配置文件),會在記憶體中開闢一塊記憶體區域專門存儲在xml文件中載入的bean,並且是以map映射的形式存儲的,key是id,value就是具體的bean。這塊記憶體區域,用於存儲bean的容器,就叫IOC容器(其實更應該叫spring的bean容器)(個人理解,實在找不到對這個定義比較好的解釋,只能先這麼理解了)。
如果看過我前一篇博客的,肯定會說依賴註入和控制反轉這不一樣嘛。。。。他倆確實是一回事。。。依賴註入也可以叫控制反轉,就是將控制權交給配置文件。。 不過我個人喜歡這樣理解:對bean的註冊叫控制反轉,對bean中參數的初始化叫依賴註入。個人覺得,知道是一回事就行,怎麼容易讓你理解怎麼來。
說一下依賴註入的好處:
最主要的還是解耦。便於數據源的切換:比如我想在print類里列印另一個bean,只需要修改xml文件即可。
這說的還是有點虛,可能真實環境更能說明問題: 公司最近遇到一個需求,需要兩撥人共同開發:一波開發公司內網介面---A組,一波開發公司對外實現(相當於客戶端)---B組。客戶端開發是依賴於內網功能的,但是又不能等待內網的同學先開發完,所以領導決定:A組的人,先把需要實現的功能,以介面(interface)的方式暴漏給B組的同學,然後兩組各自為政,開發完以後合併就行了。
假設A組暴漏了一個介面如下:
public interface MyInterface{ void myMethod(); }
但是A組這個介面的實現還沒寫,所以我B組的人想用這個介面編程,兩個辦法(我是菜鳥,可能有別的辦法,可以指點):
第一:
MyInterface bean = null;//這裡需要後期填充具體介面實現
然後,當A組的把實現給我們之後,我們再通過全局搜索,把bean全都賦值給具體的實現。這時候,萬一A組的人腦子一抽,說哎呀,我給你的實現不對,是應該給C組的,你用另一個,那我又要全局修改所有的代碼。。。。(這就是強耦合,A組修改代碼,會導致B組人代碼必須修改)
然後,第二種是醬:
用一個配置文件:
<bean id="myInterface" class="xxx.xxx.xxx.xxxx" /> <!-- 註冊我的javabean --> <bean id="printBean" class="testSpring.business.impl.Print" > <!-- 註入介面實現 --> <property name = "myInterface" ref = "myInterface"></property> </bean>
然後在我已經註冊的javaBean里只需要這樣:
private MyInterface myInterface;
就可以使用介面的具體實現了,而且無論你A組怎麼改,我B組的代碼不用修改,只改配置文件就行(當然,前提是A組的介面不能變),這就是弱耦合,也是設計原則裡面著名的依賴倒置原則(依賴介面而不依賴於具體實現)。