1. 程式人生 > >Spring入門及Ioc簡介

Spring入門及Ioc簡介

相互學習,歡迎指正,共同進步。

一、Spring概念:

  • Spring 是一個輕量級的Java開源框架,是為了解決企業應用開發的複雜性而建立的。
  • Spring 是容器框架,建立bean(相當於一個物件),維護bean之間的關係。實現了程式的解耦合和麵向切面(AOP)的容器框架
  • Spring也是一種整合性框架,可以和其他框架進行整合,從而實現多個框架的協同開發。常見的有(SSH、SSM)。

這裡簡單打個比方,介紹Spring框架的重要地位

struts2是web框架相對於銷售經理,hibernate是orm框架相當於倉庫經理,它們兩個都是非常優秀的框架,但是相互之間誰都不服誰,而Spring就相當於CEO,可以很好的管理它們,這樣好了大家都能一起愉快的協同合作了。

二、Spring的優點:

  • 方便解耦,簡化開發 (高內聚低耦合) 
    Spring就是一個大工廠(容器),可以將所有物件建立和依賴關係維護,交給Spring管理 
    spring工廠是用於生成bean
  • AOP程式設計的支援 
    Spring提供面向切面程式設計,可以方便的實現對程式進行許可權攔截、執行監控等功能
  • 宣告式事務的支援 
    只需要通過配置就可以完成對事務的管理,而無需手動程式設計
  • 方便程式的測試 
    Spring對Junit4支援,可以通過註解方便的測試Spring程式
  • 方便整合各種優秀框架 
    Spring不排斥各種優秀的開源框架,其內部提供了對各種優秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支援
  • 降低JavaEE API的使用難度 
    Spring 對JavaEE開發中非常難用的一些API(JDBC、JavaMail、遠端呼叫等),都提供了封裝,使這些API應用難度大大降低

三、Spring框架結構:

Spring 框架是一個分層架構,由 7 個定義良好的模組組成。Spring 模組構建在核心容器之上,核心容器定義了建立、配置和管理 bean 的方式。

組成 Spring 框架的每個模組(或元件)都可以單獨存在,或者與其他一個或多個模組聯合實現。每個模組的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要元件是 BeanFactory,它是工廠模式的實現。BeanFactory
     使用控制反轉 (IOC) 模式將應用程式的配置和依賴性規範與實際的應用程式程式碼分開。
  • Spring 上下文:Spring 上下文是一個配置檔案,向 Spring 框架提供上下文資訊。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和排程功能。
  • Spring AOP:通過配置管理特性,Spring AOP 模組直接將面向方面的程式設計功能整合到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何物件支援 AOP。Spring AOP 模組為基於 Spring 的應用程式中的物件提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 元件,就可以將宣告性事務管理整合到應用程式中。
  • Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同資料庫供應商丟擲的錯誤訊息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫的異常程式碼數量(例如開啟和關閉連線)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
  • Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的物件關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
  • Spring Web 模組:Web 上下文模組建立在應用程式上下文模組之上,為基於 Web 的應用程式提供了上下文。所以,Spring 框架支援與 Jakarta Struts 的整合。Web 模組還簡化了處理多部分請求以及將請求引數繫結到域物件的工作。
  • Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程式的 MVC 實現。通過策略介面,MVC 框架變成為高度可配置的,MVC 容納了大量檢視技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。

四、Spring核心思想IOC(控制反轉):

1)IOC思想:

IOC是控制反轉的簡稱,目的是為了“解耦合”。核心思想是把物件的建立、賦值和物件間的依賴關係控制權都放在IOC容器中,並在Ioc容器中進行物件之間依賴關係的繫結,因此Spring中Ioc又可以具體稱為“依賴注入(DI)”。

IOC控制反轉是一種思想,DI是Spring實現IOC的一種實現技術

2)理解物件之間的依賴關係及Ioc思想:

控制反轉IoC是說建立物件的控制權進行轉移,以前建立物件的主動權和建立時機是由自己把控的,而現在這種權力轉移到第三方

解釋一:

我們以往會使用new來建立物件,並通過setter方法設定物件與物件之間的依賴關係,new object() 這樣的語法來將物件創建出來,這個物件是由自己主動創建出來的,建立物件的主動權在自己手上,自己需要哪個物件,就主動去建立,建立物件的主動權和建立時機是由自己把控的,而這樣就會使得物件間的耦合度高了,A物件需要使用物件B來共同完成一件事,A要使用B,那麼A就對B產生了依賴,也就是A和B之間存在一種耦合關係,並且是緊密耦合在一起。

例如有一個學生物件student和一個老師物件teacher,可以通過student.setTeacher(teacher)繫結學生和老師之間的關係。但這樣學生物件就會依賴於老師物件。

而使用了Spring之後就不一樣了,建立物件B的工作是由Spring來做的,Spring建立好B物件,然後儲存到一個容器裡面,當A物件需要使用B物件時,Spring就從存放物件的那個容器裡面取出A要使用的那個B物件,然後交給A物件使用,至於Spring是如何建立那個物件,以及什麼時候建立好物件的,A物件不需要關心這些細節問題

沒懂沒關係繼續看解釋二!

解釋二:

我們在開發的時候通常的方法呼叫流程為Servlet 呼叫 Service裡的方法,Service方法呼叫DAO裡的方法,這就要求我們必須要在Service裡new一個DAO物件。

存在的問題:

(1)Service需要對DAO物件進行維護,負責這個DAO物件的整個生命週期

(2)層與層之間的依賴問題,也就是Service依賴於DAO,只有DAO開發完成才能進行Service的開發,一旦DAO裡改變比如方法名改變,那麼Service也必須修改。

(3)多個這樣的情況存在,建立的物件到處分散,給後期維護造成很大困難。

Spring如何去除依賴:

在類裡新增一個DAO介面的屬性,提供getter setter 方法,這裡體現了多型及表明了Spring是強制面向介面程式設計的。這樣做Service就不用具體new一個DAO物件,不會依賴於具體的DAO實現類。然後接下來其他的一切都交給Spring吧!

什麼?還沒懂??那就看解釋三吧!!!!

解釋三:

舉個簡單的例子,我們是如何找女朋友的?常見的情況是,我們到處去看哪裡有長得漂亮身材又好的mm,然後打聽她們的興趣愛好、電話號………,想辦法認識她們,投其所好送其所要……這個過程是複雜深奧的,我們必須自己設計和麵對每個環節。傳統的程式開發也是如此,在一個物件中,如果要使用另外的物件,就必須得到它(自己new一個),使用完之後還要將物件銷燬(比如Connection等),物件始終會和其他的介面或類藕合起來。

  那麼IoC是如何做的呢?有點像通過婚介找女朋友,在我和女朋友之間引入了一個第三者:婚姻介紹所。婚介管理了很多男男女女的資料,我可以向婚介提出一個列表,告訴它我想找個什麼樣的女朋友,比如長得像李嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術像齊達內之類的,然後婚介就會按照我們的要求,提供一個mm,我們只需要去和她談戀愛、結婚就行了。簡單明瞭,如果婚介給我們的人選不符合要求,我們就會丟擲異常。整個過程不再由我自己控制,而是有婚介這樣一個類似容器的機構來控制。Spring所倡導的開發方式就是如此,所有的類都會在spring容器中登記,告訴spring你是個什麼東西,你需要什麼東西,然後spring會在系統執行到適當的時候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的建立、銷燬都由 spring來控制,也就是說控制物件生存週期的不再是引用它的物件,而是spring。

對於某個具體的物件而言,以前是它控制其他物件,現在是所有物件都被spring控制,所以這叫控制反轉。

3)DI(依賴注入)

  IoC的一個重點是在系統執行中,動態的向某個物件提供它所需要的其他物件。這一點是通過DI(Dependency Injection,依賴注入)來實現的

比如物件A需要操作資料庫,以前我們總是要在A中自己編寫程式碼來獲得一個Connection物件,有了 spring我們就只需要告訴spring,A中需要一個Connection,至於這個Connection怎麼構造,何時構造,A不需要知道。在系統執行時,spring會在適當的時候製造一個Connection,然後像打針一樣,注射到A當中,這樣就完成了對各個物件之間關係的控制。A需要依賴 Connection才能正常執行,而這個Connection是由spring注入到A中的,依賴注入的名字就這麼來的。

那麼DI是如何實現的呢? 

Java 1.3之後一個重要特徵是反射(reflection),它允許程式在執行的時候動態的生成物件、執行物件的方法、改變物件的屬性,spring就是通過反射來實現注入的。

4)物件與類之間的耦合關係,經歷了以下三種方式

  • 通過new建立
  • 通過工廠模式獲取不同的例項工廠(需要自己寫工廠,但是物件依舊依賴於工廠,並且中間又多了一道工序)
  • 通過Ioc容器獲取不同的例項物件(只需要自己配置)


五、Spring實現IOC簡單例子:(印表機使用不同的墨水和紙張進行列印)

1)匯入jar檔案:(spring一般需要匯入5個jar檔案)

我這裡用的maven專案,pom.xml裡配置一個即可其他依賴的jar自動匯入

 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.1.6.RELEASE</version>
    </dependency>

2)定義類和介面(Spring採用的是面向介面程式設計)

墨水介面:

package org.lanqiao.printer;

public interface Ink {
	public String getColor();//獲取墨水的型別
}

紙張介面:

package org.lanqiao.printer;

public interface Paper {
	public String getSize();//獲取紙張型別
}

黑白印實現類:

package org.lanqiao.printer;

public class BlackInk implements Ink{

	@Override
	public String getColor() {
		return "黑白";
	}

}

彩印實現類:

package org.lanqiao.printer;

public class ColorInk implements Ink{

	@Override
	public String getColor() {
		return "彩色";
	}

}

A4紙張實現類:

package org.lanqiao.printer;

public class A4Paper implements Paper{

	@Override
	public String getSize() {
		return "A4";
	}

}

B5紙張實現類:

package org.lanqiao.printer;

public class B5Paper implements Paper{

	@Override
	public String getSize() {
		return "B5";
	}

}

印表機類:(印表機依賴於紙張和墨水)

package org.lanqiao.printer;

public class Printer {

	private Paper paper;// 使用紙張
	private Ink ink;	//使用墨水


	public void print(String str) {
		System.out.println("印表機正在使用" + ink.getColor() + "墨盒," + paper.getSize() + "紙列印。。。");
		System.out.println("------------------------------------------------");
		System.out.println(str);

	}

	public Paper getPaper() {
		return paper;
	}

	public void setPaper(Paper paper) {
		this.paper = paper;
	}

	public Ink getInk() {
		return ink;
	}

	public void setInk(Ink ink) {
		this.ink = ink;
	}

}

3)spring配置檔案配置bean(一個bean相當於一個物件)

<?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">
	
	<bean id="a4" class="org.lanqiao.printer.A4Paper"/><!--A4Paper a4 = new A4Paper();//多型!!-->
	<bean id="b5" class="org.lanqiao.printer.B5Paper"/>
	<bean id="b" class="org.lanqiao.printer.BlackInk"/>
	<bean id="c" class="org.lanqiao.printer.ColorInk"/>
	<bean id="printer" class="org.lanqiao.printer.Printer" >
		<property name="ink" ref="b"/>
		<property name="paper" ref="a4"/>
	</bean>
	<bean id="printer1" class="org.lanqiao.printer.Printer" >
		<property name="ink" ref="c"/>
		<property name="paper" ref="b5"/>
	</bean>
</beans>

說明:

id :                                    唯一識別符號,用來代表唯一的bean
class:                                物件的型別(包名+類名)
property:                           物件的一個屬性
property 中的name:       屬性名
property 中的value :       用於給“簡單屬性”賦值
property 中的ref:               用於給複雜屬性賦值(自定義型別的物件)

4)測試
 

package org.lanqiao.printer;


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

public class Person {
	public static void main(String[] args) {
		//建立Spring的Ioc容器物件
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		//從Ioc容器獲取Bean的例項(id為printer的Printer物件)
		Printer  p = context.getBean("printer",Printer.class);
		Printer  p1 = context.getBean("printer1",Printer.class);
		p.print("hello!!!");
		p1.print("Hello Again");
	}
}

列印結果:

如果有寫的不對的地方,歡迎大家指正!