spring的理解:
1)開源框架
2)IoC(控制反轉),將類的創建和依賴關係寫在配置文件裏,由配置文件注入,實現了鬆耦合
3)AOP 將安全,事務等於程序邏輯相對獨立的功能抽取出來,利用spring的配置文件將這些功能插進去,實現了按照方面編程,提高了複用性
或者答概念Spring是一個輕型容器(light-weight container),其核心是Bean工廠(Bean Factory),用以構造我們所需要的M(Model)。在此基礎之上,Spring提供了AOP(Aspect-Oriented Programming, 面向層面的編程)的實現,用它來提供非管理環境下申明方式的事務、安全等服務;對Bean工廠的擴展ApplicationContext更加方便我們實現J2EE的應用;DAO/ORM的實現方便我們進行數據庫的開發;Web MVC和Spring Web提供了Java Web應用的框架或與其他流行的Web框架進行集成。
Spring的核心包和核心類:
除了spring.jar文件,Spring還包括有其它13個獨立的jar包,各自包含着對應的Spring組件,用戶可以根據自己的需要來選擇組合自己的jar包,而不必引入整個spring.jar的所有類文件。
(1) spring-core.jar
這個jar文件包含Spring框架基本的核心工具類,Spring其它組件要都要使用到這個包裏的類,是其它組件的基本核心,當然你也可以在自己的應用系統中使用這些工具類。
(2) spring-beans.jar
這個jar文件是所有應用都要用到的,它包含訪問配置文件、創建和管理bean以及進行 Inversion of Control / Dependency Injection(IoC/DI)操作相關的所有類。如果應用只需基本的IoC /DI支持,引入spring-core.jar及spring- beans.jar文件就可以了。
核心類:
BeanFactory:產生一個新的實例,可以實現單例模式
BeanWrapper:提供統一的get及set方法
ApplicationContext:提供框架的實現,包括BeanFactory的所有功能
Spring的核心技術由兩大部分組成:IoC和AOP,下面我們就分別對它們進行介紹。
1 IoC技術
1.1 預備知識
IoC即Inversion of Control(控制反轉)的簡寫,它是一種設計模式,Spring只不過是實現了該模式。IoC是工廠模式的昇華,同時涉及到了反射的概念。所以,在正式介紹IoC之前,首先介紹一下幾個基本的概念及技術:接口、工廠模式、反射。
1.1.1 接口
作爲面向對象的語言,和C++不同的是,JAVA不支持多重繼承,即一個子類只能繼承自一個父類,像Son extends FatherA,FatherB 是錯誤的。於是產生了接口這個概念,即JAVA可以實現多個接口,比如:Son extends FatherA implements FatherB, FatherC是允許的。接口的主要特徵包括:
A、其中的方法均沒有實體(即只聲名未實現),就這一點而言就相當於abstact class,如:
interface ITF
{
void func(int i);
}
上例中,ITF是一個接口,它僅僅聲明瞭一個方法func,而沒有具體實現它。
B、一個類欲實現某接口,則必須實現該接口內的所有方法。例如: 字串5
class aclass implements ITF
{
public void func (int i)
{
//在這裏你可以不作任何處理,但是必須實現該方法
}
}
C、一個類可以實現多個接口。
D、接口沒有實例變量。
E、接口中所有變量都必須被定義爲final static。
F、接口可以繼承多個接口。
以上只是接口的幾個典型特徵,與其相關的內容還有很多,如果您想對其有更深的理解,請訪問其他相關資源。
1.1.2 工廠模式
工廠模式是最常用的設計模式之一(我對所謂的設計模式沒有仔細研究過,該模式是我看到次數最多的一個,所以才這麼說,呵呵)。今天看了一些例子,覺得工廠模式這個名字起得相當有創意,這是因爲在該模式中,"工廠"、"車間"、"原料"、"加工設備"、"原型產品"、"產品"等概念樣樣俱全。下面,我們在一個經典例子的基礎上,引用上述概念,對工廠模式進行較爲形象的解釋。
現在我們模擬一個火腿(Ham)加工廠,該工廠可以生產若干種類型的Ham,在該廠中,上述概念可依次描述如下:
字串8
A、"原型產品":即"產品"的模型,該模型定義(但未實現)了各類"產品"必須要具備的功能,各類"產品"對應的"加工設備"可根據該"產品"的特點實現這些功能。所以,在工廠模式中,"原型產品"可以用一個接口來表示:
- interface Ham
- {
- void show();//由Ham"加工設備"生產出的各種Ham將有show()的功能
- }
interface Ham
{
void show();//由Ham"加工設備"生產出的各種Ham將有show()的功能
}
B、"工廠":即包含了"車間"、加工所需的"原料"、"加工設備"、最終加工的"產品"等實體的複合型實體。在工廠模式中,"工廠"可以用一個類來表示,"車間"可以用該類中的函數來表示,"原料"可以用該函數中的實參來表示,最終的"產品"可以用該函數的返回值來表示。在這裏,"車間"遠程調用了"加工設備"(即每種"產品"的構造函數)。下面是"工廠"類的具體實現代碼:
- public class FatoryModule
- //"工廠"類,用於生產不同種類的Ham
- {
- public Ham getHam(String HamType) throws Exception
- //"工廠"中加工Ham的"車間";HamType爲該"車間"中的"原料"
- {
- if (HamType.equals("HamA"))
- {
- return new HamA();//根據不同的"原料"得到不同的"產品",下同
- }
- if (HamType.equals("HamB"))
- {
- return new HamB();
- }
- if (HamType.equals("HamC"))
- { 字串8
- return new HamC();
- }
- else
- throw new Exception();
- }
- public static void main(String[] args)
- //測試函數
- {
- FatoryModule fatorymodule = new FatoryModule();
- try
- {
- Ham myHam = fatorymodule.getHam(args[0]);
- myHam.show();//實際上調用的是args[0]所對應某類具體產品的show()
- }
- catch (Exception ex)
- {
- ex.printStackTrace();
- }
- }
- }
public class FatoryModule
//"工廠"類,用於生產不同種類的Ham
{
public Ham getHam(String HamType) throws Exception
//"工廠"中加工Ham的"車間";HamType爲該"車間"中的"原料"
{
if (HamType.equals("HamA"))
{
return new HamA();//根據不同的"原料"得到不同的"產品",下同
}
if (HamType.equals("HamB"))
{
return new HamB();
}
if (HamType.equals("HamC"))
{ 字串8
return new HamC();
}
else
throw new Exception();
}
public static void main(String[] args)
//測試函數
{
FatoryModule fatorymodule = new FatoryModule();
try
{
Ham myHam = fatorymodule.getHam(args[0]);
myHam.show();//實際上調用的是args[0]所對應某類具體產品的show()
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
C、"產品":即"原型產品"的模型實現實體。"車間"根據具體的"原料"調用對應的"加工設備"來實現"原型產品"定義的所有功能,最後得到所需的"產品"。所以,"產品"可以用一個類來表示,具體代碼如下:
- class HamA implements Ham
- // "產品"HamA
- {
- public void show()
- {
- System.out.println("You got a HamA.");
- }
- }
- class HamB implements Ham
- // "產品"HamB
- {
- public void show()
- {
- System.out.println("You got a HamB.");
- }
- }
- class HamC implements Ham
- // "產品"HamC
- {
- public void show()
- {
- System.out.println("You got a HamC.");
- }
- }
class HamA implements Ham
// "產品"HamA
{
public void show()
{
System.out.println("You got a HamA.");
}
}
class HamB implements Ham
// "產品"HamB
{
public void show()
{
System.out.println("You got a HamB.");
}
}
class HamC implements Ham
// "產品"HamC
{
public void show()
{
System.out.println("You got a HamC.");
}
}
小結:總體感覺工廠模式是接口的典型應用。該模式最大特點是方便我們"加工"指定參數條件下的產品。以上述情況爲例,假如我們不採用該模式的話,要得到一種產品就必須new一個該產品類的實例,而且在程序中不同產品類的實例變量不能採用同一個變量名。假如有一天我們想更換某一類產品的名字,考慮到程序的可讀性,該類產品的實例變量名也需要修改,這個工作量也需會很大(所有涉及到該變量名的地方都需要修改)。從這一點來講,工廠模式能夠減輕我們代碼維護量。
1.1.3 反射(主要應用於Spring的四種Bean封裝機制中的Bean Wrapper機制)
反射是java的一種非常有趣且有用的特徵,而且也是Java被視爲動態(或準動態)語言的一個非常關鍵的性質。該機制允許java程序在運行時通過Reflection APIs(java.lang.reflect.*)取得任何一個已知名稱的class的內部信息,包括其modifiers(諸如public, static 等等)、superclass(如Object等)、所實現的interfaces(如Cloneable等),以及fields和methods的所有信息,並可在程序運行時改變fields的內容或喚起methods。其實,反射的最重要作用就是允許我們通過類(方法)名調用類(方法)。
更具體的內容請看候捷先生的文章:"Java反射機制",具體網址爲:http://www.j2medev.com/Article/Class3/Class7/200604/1995.html。如果您想在短時間內對java的反射機制有一個大體的瞭解,請看一個網友的一篇博客:"java的reflect機制(反射)",網址爲:http://jackleliu.spaces.live.com/blog/cns!426307897fa1054e!125.entry。
1.2 正式進入IoC
IoC實際上是一個高層次的概念,是一種思想或者設計模式,Spring等J2EE框架或者技術只不過是該思想的實現產品。簡單的來講,IoC要求我們利用容器,而不是我們自己編寫的代碼去控制系統中應用程序之間的關係。即對應用程序之間的關係由原來的手工編碼控制轉換爲利用容器控制。所以,我們把這種思想叫做控制反轉(IoC)。
IoC有多種實現方法,其中,Spring是通過一種名爲DI(Dependency Injection,即依賴注入)的方法實現的。用夏昕先生的話來講,"所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關係注入到組件之中。"在Spring中,上面所說的容器一般是一種配置文件(.Xml等類型的文件)。
通過使用DI,當組件之間關係發生變化時,我們只需要修改系統中相關的配置文件,不需要改動我們的代碼,這既減少了我們的程序維護量,又提高了我們程序的可重用性。
DI主要有三種實現方式:接口注入、設值注入、構造子注入,下面分別加以介紹:
1.2.1 接口注入
該方式利用接口將調用組件和實現組件相分離。請看下面的代碼:
- public class ClassA
- {
- private InterfaceB clzB;
- public Object doSomething(InterfaceB b)
- {
- clzB = b;
- return clzB.doIt();
- }
- ………
- }
public class ClassA
{
private InterfaceB clzB;
public Object doSomething(InterfaceB b)
{
clzB = b;
return clzB.doIt();
}
………
}
上面的實參b的值由容器(spring中的相關配置文件)定義,並在運行期間由該容器提供。相關配置文件的內容我們以後會專門加以介紹。
1.2.2 設值注入
設值注入是spring中應用最廣泛的DI模式,與其它模式相比,該模式更爲直觀、自然。該模式主要通過類的setter方法來完成依賴關係的設置。請看下面的代碼:
- public class DIByConstructor
- {
- private final DataSource dataSource;
- private final String message;
- ………
- public setDataSource(DataSource ds)
- {
- this.dataSource = ds;
- }
- public setmessage(String msg)
- {
- this.message = msg;
- }
- public getDataSource()
- {
- return this.dataSource;
- }
- public getmessage()
- {
- return this.message;
- }
- ………
- }
public class DIByConstructor
{
private final DataSource dataSource;
private final String message;
………
public setDataSource(DataSource ds)
{
this.dataSource = ds;
}
public setmessage(String msg)
{
this.message = msg;
}
public getDataSource()
{
return this.dataSource;
}
public getmessage()
{
return this.message;
}
………
}
上面的實參ds和msg的值由容器(spring中的相關配置文件)定義,並在運行期間由該容器提供。相關配置文件的內容我們以後會專門加以介紹。
1.2.3 構造子注入
構造子注入,即通過構造函數完成依賴關係的設定,請看下面的代碼:
- public class DIByConstructor
- {
- private final DataSource dataSource;
- private final String message;
- public DIByConstructor(DataSource ds, String msg)
- {
- this.dataSource = ds;
- this.message = msg;
- }
- }
public class DIByConstructor
{
private final DataSource dataSource;
private final String message;
public DIByConstructor(DataSource ds, String msg)
{
this.dataSource = ds;
this.message = msg;
}
}
可以看到,在該模式中,依賴關係是通過類構造函數建立的,容器通過調用類的構造方法,將其所需的依賴關係注入其中。其中,構造函數的實參ds和msg的值由容器(spring中的相關配置文件)定義,並在運行期間由該容器提供。相關配置文件的內容我們以後會專門加以介紹。
1.2.4 幾種注入模式的比較
個人覺得,這部分屬於理論研究的範疇,所以在此不予介紹。如果您對此感興趣的話,請參考相關資料。
2 AOP技術
2.1 AOP基本概念
AOP(Aspect-Oriented Programming,面向切面編程)是一種程序設計思想,該思想的主要目標是將系統分爲兩部分:一部分封裝了系統中各組件的通用功能(羅輯或者責任),形成一個切面,該切面被稱爲應用系統的"橫切關注點",此部分包含了與系統核心商業邏輯關係不大的部分;系統的其餘部分,即核心商業邏輯部分,被稱爲系統的"核心關注點",此部分包含了系統中業務處理的主要流程。其中,"橫切關注點"經常出現在"核心關注點"的周圍,但無論出現在何處,它們的基本功能是相似的,比如權限認證、日誌、事務處理等。應用中採用這種思想的好處在於:一方面可以使我們在系統開發過程中的責任分工更爲明確(比如,可以讓高級工程師負責"橫切關注點"的開發,初級工程師負責"核心關注點"的開發,配置工程師負責將以上兩部分搭建成一個完整的應用系統);另一方面,清晰的系統結構將使我們以後的系統維護工作變得更爲輕鬆。
字串3
下面是AOP的幾個基本概念(理解它們極爲重要):
2.1.1 Join point(連接點):是程序執行中的一個精確執行點,例如類中的一個方法。它是一個抽象的概念,在實現AOP時,並不需要去定義一個Join point。
2.1.2 Point cut(切入點):本質上是一個捕獲連接點的結構(或稱連接點的集合)。在AOP中,可以定義一個Point cut,來捕獲相關方法(通知中的邏輯)的調用。
2.1.3 Advice(通知):Point cut的執行代碼,它是執行"切面"的具體邏輯。
2.1.4 Aspect(切面):Point cut和Advice的組合,它類似於OOP中定義的一個類,但它代表的更多的是對象間橫向的關係。
2.1.5 Introduce(引入):爲對象引入附加的方法或屬性,從而達到修改對象結構的目的(此概念不是很理解)。
2.1.6 Target Object(目標對象):包含Join point的對象,它是被Advice的類,也是商務邏輯對象。這個對象永遠是一個被代理的對象。
2.1.7 AOP Proxy(AOP代理):由AOP框架創建的對象,它是真正執行Advice的實體。
2.1.8 Weaving(織入):將Aspec模塊與核心商務邏輯(即目標對象)進行關聯的過程,比如,將事務處理模塊和銀行櫃員機程序通過配置結合起來,決定什麼情況下事務處理模塊被通知調用。 字串3
2.2 AOP in Spring2.0應用程序開發基本步驟
在2.0版本以前,Spring所提供的內置AOP支持是基於Java Dynamic Proxy和CGLib實現的,是一種動態的AOP機制。Spring 2.0版本之後,AOP的使用變得更簡單,同時功能也更爲強大。通過與AspectJ 5的整合, Spring 2.0提供了更完整的AOP。在Spring 2.0中,AOP主要有三種實現方式:基於AspectJ語言的實現方式;基於模式(schema-based)的實現方式;基於 Dynamic Proxy和CGLib(即同以前版本的Spring是兼容的)的實現方式。
下面是一個用Spring2.0的AOP所做的一個例子,該例採用了上面所說的第一種實現方式。限於篇幅,有關AspectJ方面的內容這裏不再敘述,您可以參考相關的資料以對其有一個基本的瞭解。另外,可以通過MyEclipse最新版本實現該例,該版本提供了對Spring2.0的全面支持。
Step1 首先創建一個普通的Java項目:com.longthsoft.learn.spring
Step2 然後編寫兩個簡單的類,代碼如下:
- package com.longthsoft.learn.spring.models;
- public class A //"目標對象"A,AOP框架將自動爲該對象創建一個"代理對象"
- {
- public void sayHello()
- {
- System.out.println("Hello, I'm a");
- }
- };
package com.longthsoft.learn.spring.models;
public class A //"目標對象"A,AOP框架將自動爲該對象創建一個"代理對象"
{
public void sayHello()
{
System.out.println("Hello, I'm a");
}
};
- package com.longthsoft.learn.spring.models;
- public class B //"目標對象"B,AOP框架將自動爲該對象創建一個"代理對象"
- {
- public void sayHi()
- {
- System.out.println("Hi, I'm b"); 字串1
- }
- }
package com.longthsoft.learn.spring.models;
public class B //"目標對象"B,AOP框架將自動爲該對象創建一個"代理對象"
{
public void sayHi()
{
System.out.println("Hi, I'm b"); 字串1
}
}
Step3 接下來編寫AOP中的"切面"類,代碼如下:
- package com.longthsoft.learn.spring;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect //利用AspectJ語法創建一個"切面"
- public class SimpleAspect
- {
- @Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")
- //創建"切入點",該"切入點"捕獲了指定項目中相關類的方法("連接點")
- public void simplePointcut() { }
- @AfterReturning(pointcut="simplePointcut()")
- 字串4
- //創建"通知",該"通知"綁定了具體的"切入點"
- public void simpleAdvice() //"切入點"的執行代碼,將被"目標對象"的"代理對象"執行
- {
- System.out.println("Merry Christmas");
- }
- }
package com.longthsoft.learn.spring;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect //利用AspectJ語法創建一個"切面"
public class SimpleAspect
{
@Pointcut("execution(* com.longthsoft.learn.spring.models.*.say*())")
//創建"切入點",該"切入點"捕獲了指定項目中相關類的方法("連接點")
public void simplePointcut() { }
@AfterReturning(pointcut="simplePointcut()")
字串4
//創建"通知",該"通知"綁定了具體的"切入點"
public void simpleAdvice() //"切入點"的執行代碼,將被"目標對象"的"代理對象"執行
{
System.out.println("Merry Christmas");
}
}
Step4 編寫配置文件(applicationContext.xml),內容如下:
- <?xml version="1.0" encoding="GBK"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
- <aop:aspectj-autoproxy /> //織入"目標對象"和"切面"之間的關聯關係
- <bean id="a" class="com.longthsoft.learn.spring.models.A" />
- <bean id="b" class="com.longthsoft.learn.spring.models.B" />
- <bean id="simpleAspect" class="com.longthsoft.learn.spring.SimpleAspect" />
- </beans>
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<aop:aspectj-autoproxy /> //織入"目標對象"和"切面"之間的關聯關係
<bean id="a" class="com.longthsoft.learn.spring.models.A" />
<bean id="b" class="com.longthsoft.learn.spring.models.B" />
<bean id="simpleAspect" class="com.longthsoft.learn.spring.SimpleAspect" />
</beans>
Step5 編寫測試程序,代碼如下:
- package com.longthsoft.learn.spring;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import com.longthsoft.learn.spring.models.A;
- import com.longthsoft.learn.spring.models.B;
- public final class Boot
- {
- public static void main(String[] args)
- {
- ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
- A a = (A) ctx.getBean("a");
- a.sayHello();
- B b = (B) ctx.getBean("b");
- b.sayHi();
- }
- }
package com.longthsoft.learn.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.longthsoft.learn.spring.models.A;
import com.longthsoft.learn.spring.models.B;
public final class Boot
{
public static void main(String[] args)
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
A a = (A) ctx.getBean("a");
a.sayHello();
B b = (B) ctx.getBean("b");
b.sayHi();
}
}
最後運行結果如下:
Hello, I'm a
Merry Christmas
Hi, I'm b
Merry Christmas