http://penghuaiyi.iteye.com/blog/182616
這段時間,看了一些Spring文檔和資料,對其有了一個基本的了解。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、"原型產品":即"產品"的模型,該模型定義(但未實現)了各類"產品"必須要具備的功能,各類"產品"對應的"加工設備"可根據該"產品"的特點實現這些功能。所以,在工廠模式中,"原型產品"可以用一個接口來表示:
Java代碼
- interface Ham
- {
- void show();//由Ham"加工設備"生產出的各種Ham將有show()的功能
- }
B、"工廠":即包含了"車間"、加工所需的"原料"、"加工設備"、最終加工的"產品"等實體的復合型實體。在工廠模式中,"工廠"可以用一個類來表示,"車間"可以用該類中的函數來表示,"原料"可以用該函數中的實參來表示,最終的"產品"可以用該函數的返回值來表示。在這里,"車間"遠程調用了"加工設備"(即每種"產品"的構造函數)。下面是"工廠"類的具體實現代碼:
Java代碼
- 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、"產品":即"原型產品"的模型實現實體。"車間"根據具體的"原料"調用對應的"加工設備"來實現"原型產品"定義的所有功能,最后得到所需的"產品"。所以,"產品"可以用一個類來表示,具體代碼如下:
Java代碼
- 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 接口注入
該方式利用接口將調用組件和實現組件相分離。請看下面的代碼:
Java代碼
- public class ClassA
- {
- private InterfaceB clzB;
- public Object doSomething(InterfaceB b)
- {
- clzB = b;
- return clzB.doIt();
- }
- ………
- }
上面的實參b的值由容器(spring中的相關配置文件)定義,并在運行期間由該容器提供。相關配置文件的內容我們以后會專門加以介紹。
1.2.2 設值注入
設值注入是spring中應用最廣泛的DI模式,與其它模式相比,該模式更為直觀、自然。該模式主要通過類的setter方法來完成依賴關系的設置。請看下面的代碼:
Java代碼
- 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 構造子注入
構造子注入,即通過構造函數完成依賴關系的設定,請看下面的代碼:
Java代碼
- 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 然后編寫兩個簡單的類,代碼如下:
Java代碼
- package com.longthsoft.learn.spring.models;
- public class A //"目標對象"A,AOP框架將自動為該對象創建一個"代理對象"
- {
- public void sayHello()
- {
- System.out.println("Hello, I'm a");
- }
- };
Java代碼
- package com.longthsoft.learn.spring.models;
- public class B //"目標對象"B,AOP框架將自動為該對象創建一個"代理對象"
- {
- public void sayHi()
- {
- System.out.println("Hi, I'm b"); 字串1
- }
- }
Step3 接下來編寫AOP中的"切面"類,代碼如下:
Java代碼
- 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),內容如下:
Java代碼
- <?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 編寫測試程序,代碼如下:
Java代碼
- 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
3 引用資源
3.1 候捷 《Java反射機制》
3.2 夏昕 《Spring開發指南 V0.8》
3.3 佚名 《AOP技術介紹--(AOP技術基礎)》