1. 程式人生 > >6. Spring的AOP

6. Spring的AOP

一、基本概念

1. AOP(Aspect Oriented Programming),即面向切面程式設計,可以說是OOP(Object Oriented Programming,面向物件程式設計)的補充和完善
2. 利用一種稱為“橫切”的技術,剖解開封裝的物件內部,並將那些影響了多個類的公共行為封裝到一個可重用模組,並將其名為“Aspect”,即方面
3. 所謂“方面”,簡單地說,就是將那些與業務無關,卻為業務模組所共同呼叫的邏輯或責任封裝起來,便於減少系統的重複程式碼,降低模組間的耦合度,並有利於未來的可操作性和可維護性
4. 使用"橫切"技術,AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點
5. 橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處基本相似,比如許可權認證、日誌、事務。AOP的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來

二、核心名詞

1. 橫切關注點題
1) 對哪些方法進行攔截,攔截後怎麼處理,這些關注點稱之為橫切關注點
2. 切面(aspect)
1) 類是對物體特徵的抽象,切面就是對橫切關注點的抽象

2) 是切入點和通知的結合,以後咱們自己來編寫和配置的
3. 連線點(joinpoint)
1) 被攔截到的點,因為Spring只支援方法型別的連線點,所以在Spring中連線點指的就是被攔截到的方法,實際上連線點還可以是欄位或者構造器

2) 程式執行中的一些時間點, 例如一個方法的執行, 或者是一個異常的處理

4. 切入點(pointcut)
1) 對連線點進行攔截的定義

2) 在 Spring 中, 所有的方法都可以認為是 joinpoint, 但是我們並不希望在所有的方法上都新增 Advice, 而 pointcut 的作用就是提供一組規則(使用 AspectJ pointcut expression language 來描述) 來匹配joinpoint, 給滿足規則的 joinpoint 新增 Advice

3) advice 是在 join point 上執行的, 而 point cut 規定了哪些 join point 可以執行哪些 advice
5. 通知(advice)
1) 所謂通知指的就是指攔截到連線點之後要執行的程式碼

2) 通知種類:

	(1)前置通知: 在目標類的方法執行之前執行

	 	配置檔案資訊:<aop:after method="before" pointcut-ref="myPointcut3"/>

	 	應用:可以對方法的引數來做校驗

	(2)最終通知: 在目標類的方法執行之後執行,如果程式出現了異常,最終通知也會執行	

		配置檔案資訊:<aop:after method="after" pointcut-ref="myPointcut3"/>

		應用:例如像釋放資源

	(3)後置通知:	方法正常執行後的通知	

		配置檔案資訊:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>

		應用:可以修改方法的返回值

	(4)異常丟擲通知:在丟擲異常後通知	

		配置檔案資訊:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>

		應用:包裝異常的資訊

	(5)環繞通知:方法的執行前後執行	

		配置檔案資訊: <aop:around method="around" pointcut-ref="myPointcut2"/>

		要注意:目標的方法預設不執行,需要使用ProceedingJoinPoint對來讓目標物件的方法執行

6. 目標物件
1) 代理的目標物件

2) 織入 advice 的目標物件. 目標物件也被稱為 advised object
7. 織入(weave)
1) 將切面應用到目標物件並導致代理物件建立的過程

2) 將 aspect 和其他物件連線起來, 並建立 adviced object 的過程
8.引入(introduction)
1) 在不修改程式碼的前提下,引入可以在執行期為類動態地新增一些方法或欄位
9. Proxy(代理)
1) 一個類被AOP織入增強後,就產生一個結果代理類

2) 它是融合了原類和增強邏輯的代理類.在 Spring AOP 中, 一個 AOP 代理是一個 JDK 動態代理物件或 CGLIB 代理物件.

三、AOP程式設計

1. Spring對AOP的支援
Spring中AOP代理由Spring的IOC容器負責生成、管理,其依賴關係也由IOC容器負責管理。因此,AOP代理可以直接使用容器中的其它bean例項作為目標,這種關係可由IOC容器的依賴注入提供。Spring建立代理的規則為:

1)預設使用Java動態代理來建立AOP代理,這樣就可以為任何介面例項建立代理了

2)當需要代理的類不是代理介面的時候,Spring會切換為使用CGLIB代理,也可強制使用CGLIB

2. aop程式設計步驟步驟:進行AOP程式設計的關鍵就是定義切入點和定義增強處理,一旦定義了合適的切入點和增強處理,AOP框架將自動生成AOP代理 (代理物件的方法=增強處理+被代理物件的方法)
1)定義普通業務元件

2)定義切入點,一個切入點可能橫切多個業務元件

3)定義增強處理,增強處理就是在AOP框架為普通業務元件織入的處理動作
3. springAOP的具體載入步驟
1)當 spring 容器啟動的時候,載入了 spring 的配置檔案

2)為配置檔案中的所有 bean 建立物件

3) spring 容器會解析 aop:config 的配置

4) 解析切入點表示式,用切入點表示式和納入spring容器中的bean做匹配, 如果匹配成功,則會為該bean建立代理物件,代理物件的方法=目標方法+通知,如果匹配不成功,不會建立代理物件

5) 在客戶端利用 context.getBean() 獲取物件時,如果該物件有代理物件,則返回代理物件;如果沒有,則返回目標物件

4. 一般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"
    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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>

5. 註解配置
1)寫切面類

	@Aspect
	@Component
	public class ReadThroughAssignAop extends SingleReadCacheAdvice {

	    private static final Logger LOG = LoggerFactory.getLogger(ReadThroughAssignAop.class);

	    // 定義切入點,定義切入表示式(帶@ReadCache註解的)
	    @Pointcut("@annotation(com.pagoda.redis.annotation.ReadCache)")
	    public void getSingleAssign() {

	    }

	    // 定義通知,以及需要連線到的切入點(通過方法名關聯上)
	    @Around("getSingleAssign()")
	    public Object cacheSingleAssign(final ProceedingJoinPoint jp) throws Throwable {
	        // to do 作通知的操作
	        return cache(jp);
	    }

	    @Override
	    protected Logger getLogger() {
	        return LOG;
	    }


	}

2)spring中配置

    <!-- redis快取執行切面 -->
    <bean id="RedisCacheAspect"  class="com.pagoda.redis.aop.ReadThroughAssignAop" />

    <!-- 切面申明配置-->
    <aop:aspectj-autoproxy>
        <aop:include name="RedisCacheAspect" />
    </aop:aspectj-autoproxy>	

四、運用場景

1. 效能檢測
2. 許可權驗證
3. 日誌記錄
4. 事務控制
5. 整合redis 
6. 錯誤處理
7. 快取

參考網址

注:文章是經過參考其他的文章然後自己整理出來的,有可能是小部分參考,也有可能是大部分參考,但絕對不是直接轉載,覺得侵權了我會刪,我只是把這個用於自己的筆記,順便整理下知識的同時,能幫到一部分人。
ps : 有錯誤的還望各位大佬指正,小弟不勝感激