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
- 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");
}
}
列印結果:
如果有寫的不對的地方,歡迎大家指正!