關於Spring的IOC原理

 Spring   IOC原理


內部最核心的就是IOC了,直觀地講,就是容器控制程序之間的關係,而非傳統實現中,由程序代碼直接操控。這也就是所謂「控制反轉」的概念所在。控制權由應用代碼中轉到了外部容器,控制權的轉移是所謂反轉。html

IoC還有另一個名字——「依賴注入(Dependency Injection)」。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象地說,即由容器動態地將某種依賴關係注入到組件之中。java


依賴注入的三種實現類型:接口注入、 Setter 注入和構造器注入。
web

一、接口注入spring

public class ClassA 
{ 
private InterfaceB clzB; 
public void doSomething() { 
Ojbect obj =Class.forName(Config.BImplementation).newInstance(); 
clzB = (InterfaceB)obj; 
clzB.doIt() 
} 
…… 
}
上面的代碼中, ClassA 依賴於 InterfaceB  的實現,如何得到 InterfaceB 實現類的實例?傳統的方法是在代碼中建立 InterfaceB 實現類的實例,並將起賦予 clzB 。  而這樣一來,  ClassA 在編譯期即依賴於 InterfaceB  的實現。爲了將調用者與實現者在編譯期分離,因而有了上面的代碼.  咱們根據預先在配置文件中設定的實現類的類名  (Config.BImplementation) ,動態加載實現類,並經過 InterfaceB 強制轉型後爲 ClassA  所用。這就是接口注入的一個最原始的雛形。  而對於一個 接口 型 IOC  容器而言,加載接口實現並建立其實例的工做由容器完成,見以下代碼。 

public class ClassA 
{ 
private InterfaceB clzB; 
public Object doSomething(InterfaceB b) 
{ 
clzB = b; 
return clzB.doIt(); 
} 
…… 
}
在運行期, InterfaceB 實例將由容器提供。 接口型 IOC 發展較早(有意或無心),在實際中獲得了廣泛應用,即便在 IOC 
的概念還沒有確立時,這樣的方法也已經頻繁出如今咱們的代碼中。
public class 
MyServlet extends HttpServlet { 
public void doGet(HttpServletRequest 
request,HttpServletResponse response)throws ServletException, IOException { …… } 
}
上面的代碼應該有印象吧
這也是一個 接口 型注入, HttpServletRequest 和 HttpServletResponse 實例由 Servlet  Container 在運行期動態注入。 


二、Setter( 設值 ) 注入 數據庫

各類類型的依賴注入模式中,設值注入模式在實際開發中獲得了最普遍的應用。
編程

public class 
ClassA { 
private InterfaceB clzB; 
public void setClzB(InterfaceB clzB) 
{ 
this. clzB = clzB; } 
…… 
}


再以下面的例子:

這裏是TextEditor.java文件的內容:
架構

package com.yiibai;

public class TextEditor {
   private SpellChecker spellChecker;

   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }

   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
在這裏,須要檢查setter方法​​的命名約定。設置咱們使用setSpellChecker()方法,這是很是相似於Java POJO類的變量的拼寫檢查器。讓咱們創造另外一個相關的類文件SpellChecker.java,內容以下:
package com.yiibai;

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }

   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   }
   
}
如下是MainApp.java文件的內容:

package com.yiibai;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = 
             new ClassPathXmlApplicationContext("Beans.xml");

      TextEditor te = (TextEditor) context.getBean("textEditor");

      te.spellCheck();
   }
}
配置文件爲

<?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-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.yiibai.TextEditor">
      <property name="spellChecker" ref="spellChecker"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.yiibai.SpellChecker">
   </bean>

</beans>

三、構造器注入 

依賴關係是經過類構造函數創建的 容器經過調用類的構造方法將其所需的依賴關係注入其中 app

public 
class DIByConstructor { private final DataSource dataSource; 
public 
DIByConstructor(DataSource ds) { 
this.dataSource = ds; 
} 
…… 
}
再以下例子:

在須要注入的類中,編寫注入的構造方法框架

public PersonServiceBean(PersonDao personDao, String string) {
		this.personDao = personDao;
		this.string = string;
	}
在beans.xml中申明被注入的類

<bean id="personDao" class="com.dwt1220.PersonDaoBean" />
在注入類的<bean>標籤體中使用<constructor-arg>標籤

<bean id="personService" class="com.dwt1220.PersonServiceBean">
		<!--index=構造方法的參數位置(下標從0開始), type=注入的類型,ref=注入類在beans.xml中註冊的ID -->
		<constructor-arg index="0" type="com.dwt1220.PersonDao" ref="personDao"/>
		<constructor-arg index="1" value="dwt1220" />
	</bean>
PersonServiceBean.java類

package com.dwt1220;

public class PersonServiceBean implements PersonService {
	private PersonDao personDao;
	private String string;
	
	public PersonServiceBean(PersonDao personDao, String string) {
		this.personDao = personDao;
		this.string = string;
	}

	public PersonDao getPersonDao() {
		return personDao;
	}

	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}

	public void save() {
		System.out.println("這是save方法");
		System.out.println(string);
	}
}
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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
	<bean id="personDao" class="com.dwt1220.PersonDaoBean" />
	<bean id="personService" class="com.dwt1220.PersonServiceBean">
		<!--index=構造方法的參數位置(下標從0開始), type=注入的類型,ref=注入類在beans.xml中註冊的ID -->
		<constructor-arg index="0" type="com.dwt1220.PersonDao" ref="personDao"/>
		<constructor-arg index="1" value="dwt1220" />
	</bean>
</beans>
Test.java

package com.dwt1220;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
	public static void main(String[] args) {
		AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
		PersonService personService = (PersonService) ctx.getBean("personService");
		personService.save();
		ctx.close();
	}
}

動態注入,讓一個對象的建立不用new了,能夠自動的生產,這其實就是利用java裏的反射  
反射其實就是在運行時動態的去建立、調用對象,Spring就是在運行時,跟xml Spring的配置  

文件來動態的建立對象,和調用對象裏的方法的 。  yii


Spring它是一個開源的項目,並且目前很是活躍;它基於IoC(Inversion of Control,反向控制)和AOP的構架多層j2ee系統的框架,但它不強迫你必須在每一層 中必須使用Spring,由於它模塊化的很好,容許你根據本身的須要選擇使用它的某一個模塊;它實現了很優雅的MVC,對不一樣的數據訪問技術提供了統一的 接口,採用IoC使得能夠很容易的實現bean的裝配,提供了簡潔的AOP並據此實現Transcation Managment,等等


優勢  
a. Spring能有效地組織你的中間層對象,無論你是否選擇使用了EJB。若是你僅僅使用了Struts或其餘爲J2EE的 API特製的framework,Spring致力於解決剩下的問題。  
b. Spring能消除在許多工程中常見的對Singleton的過多使用。根據個人經驗,這是一個很大的問題,它下降了系統的可測試性和麪向對象的程度。  
c. 經過一種在不一樣應用程序和項目間一致的方法來處理配置文件,Spring能消除各類各樣自定義格式的屬性文件的須要。曾經對某個類要尋找的是哪一個魔法般的屬性項或系統屬性感到不解,爲此不得不去讀Javadoc甚至源編碼?有了Spring,你僅僅須要看看類的JavaBean屬性。Inversion of Control的使用(在下面討論)幫助完成了這種簡化。  
d. 經過把對接口編程而不是對類編程的代價幾乎減小到沒有,Spring可以促進養成好的編程習慣。  
e. Spring被設計爲讓使用它建立的應用盡量少的依賴於他的APIs。在Spring應用中的大多數業務對象沒有依賴於Spring。  
f. 使用Spring構建的應用程序易於單元測試。  
g. Spring能使EJB的使用成爲一個實現選擇,而不是應用架構的必然選擇。你能選擇用POJOs或local EJBs來實現業務接口,卻不會影響調用代碼。  
h. Spring幫助你解決許多問題而無需使用EJB。Spring能提供一種EJB的替換物,它們適用於許多web應用。例如,Spring能使用AOP提供聲明性事務管理而不經過EJB容器,若是你僅僅須要與單個數據庫打交道,甚至不須要一個JTA實現。  
i. Spring爲數據存取提供了一個一致的框架,不管是使用的是JDBC仍是O/R mapping產品(如Hibernate)。  
Spring確實使你能經過最簡單可行的解決辦法來解決你的問題。而這是有有很大價值的。


使用IOC框架應該注意什麼
使用IOC框架產品可以給咱們的開發過程帶來很大的好處,可是也要充分認識引入IOC框架的缺點,作到心中有數,杜絕濫用框架。
第1、軟件系統中因爲引入了第三方IOC容器,生成對象的步驟變得有些複雜,原本是二者之間的事情,又憑空多出一道手續,因此,咱們在剛開始使用IOC框架的時候,會感受系統變得不太直觀。因此,引入了一個全新的框架,就會增長團隊成員學習和認識的培訓成本,而且在之後的運行維護中,還得讓新加入者具有一樣的知識體系。
第2、因爲IOC容器生成對象是經過反射方式,在運行效率上有必定的損耗。若是你要追求運行效率的話,就必須對此進行權衡。
第3、具體到IOC框架產品(好比:Spring)來說,須要進行大量的配製工做,比較繁瑣,對於一些小的項目而言,客觀上也可能加大一些工做成本。
第4、IOC框架產品自己的成熟度須要進行評估,若是引入一個不成熟的IOC框架產品,那麼會影響到整個項目,因此這也是一個隱性的風險。
咱們大致能夠得出這樣的結論:一些工做量不大的項目或者產品,不太適合使用IOC框架產品。另外,若是團隊成員的知識能力欠缺,對於IOC框架產品缺少深刻的理解,也不要貿然引入。最後,特別強調運行效率的項目或者產品,也不太適合引入IOC框架產品,象WEB2.0網站就是這種狀況。
相關文章
相關標籤/搜索