Spring學習筆記|第二篇:Spring-AOP

1.AOP概念

在開發過程中會產生一些與主業務邏輯關係不大,但散落在代碼各個部分難以維護的橫切性問題,如日誌記錄、權限驗證、事務管理、異常處理等。AOP就是處理這些橫切性問題,AOP思想就是將這些問題與主業務分開,從而達到與主業務解耦的目的。

2.AOP術語

(1) Join point: 連接點,目標對象中的方法

(2) Advice: 通知,特定連接點上具體操作,具體有"around"、"before"和"after"三種通知

(3) Pointcut: 切點,多個連接點的集合,可用表達式表示目標連接點集合

(4) Target object: 目標對象,即需要增加的對象

(5) Aop proxy: 代理對象,Aop底層爲jdk動態代理和cgLib代理,aop實質即爲目標對象生成代理對象,從而對目標對象進行增強

(6) Weaving: 織入,將需要增強的通知增強進目標對象中

3. @AspectJ 支持

Spring對Aop的支持,底層自己實現了一套AOP邏輯,只是引入了AspectJ的註解支持,AOP是一種概念,SpringAop、AspectJ均爲Aop的實現,Spring實現的Aop邏輯複雜,故引入了AspectJ的註解,底層仍爲自己實現

3.1 Spring中引入切面實現

(1) 引入AspectJ依賴,目的爲提供AspectJ註解支持

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

(2) 配置文件中增加@EnableAspectJAutoProxy

@Configuration
@ComponentScan("com.study.spring")
@EnableAspectJAutoProxy
public class SpringConfig {

}

(3) 書寫切面對象,並將該對象交由Spring管理

@Aspect
@Component
public class UserAop {

}

(4)書寫切入點

@Pointcut("execution(* com.study.spring.dao.*(..))")
public void pointCut(){

}

(5)書寫通知即可完成切面實現

@Before("pointCut()")
public void beforeAdvice(){
    System.out.println("before advice");
}

3.2 pointcut切面表達式

  • execution

表示匹配連接點對應的包及其子包對象及對象中的方法,最小作用單元爲方法級別

execution(* * com.study.spring.dao.*.*(..))

表示式解析:

第一個*:表示方法訪問級別,可以爲public,private,protect,下述表達式表示只會給訪問級別爲public的方法進行增aop

execution(public * com.study.spring.dao.*.*(..))

第二個*:表示方法返回類型,下述表達式表示只會給沒有返回值的方法進行aop

execution(void com.study.spring.dao.*.*(..))

第三個表示式:表示方法路徑,下述表示dao包及其所有子包,對應所有方法均爲被增強

execution(* com.study.spring.dao..*(..))

execution表達式爲我們常用表達式,表達式也比較多,在此就不做過多介紹,實際開發中可根據實際需求進行配置

  • within

表示匹配連接點對應的包及其子包對象,最小作用單元爲對象級別

(1)表示dao包下所有對象均會被增強

within(void com.study.spring.dao.*)

(2)下述表達式表示dao包及其子包中所有對象均會被增強

within(void com.study.spring.dao..*)
  • target 及this

target:表示目標對象,即aop對應的原始對象
this:表示代理對象

/**
 * 此處需要注意的是,如果配置設置proxyTargetClass=false,或默認爲false,則是用JDK代理,否則使用的是CGLIB代理
 * JDK代理的實現方式是基於接口實現,代理類繼承Proxy,實現接口。
 * 而CGLIB繼承被代理的類來實現。
 * 所以使用target會保證目標不變,關聯對象不會受到這個設置的影響。
 * 但是使用this對象時,會根據該選項的設置,判斷是否能找到對象。
 */
@Pointcut("target(com.study.dao.IndexDaoImpl)")//目標對象,也就是被代理的對象。限制目標對象爲com.study.dao.IndexDaoImpl類
@Pointcut("this(com.study.dao.IndexDaoImpl)")//當前對象,也就是代理對象,代理對象時通過代理目標對象的方式獲取新的對象,與原值並非一個
@Pointcut("@target(com.study.anno.ExtAnno)")//具有@ExtAnno的目標對象中的任意方法
@Pointcut("@within(com.study.anno.ExtAnno)")//等同於@target
  • @target、@arges、@within、@annotation

帶有@,與上述表示方式類似,唯一區別在於這些表達式只針對於註解形式

切點配置的表達式較大,可根據實際開發中所遇具體配置,在此不做過多介紹

3.3 Advice通知

(1)前置通知(@before):表示在方法執行前進行增強

@Before("pointCut()")
public void beforeAdvice(){
    System.out.println("before advice");
}

(2)後置通知(@After):表示在方法執行後進行增強

 @After("pointCut()")
  public void beforeAdvice(){
    System.out.println("after advice");
  }

(3)環繞通知(@Around):表示在方法執行前、執行後均增強

@Around("pointCut()")
public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("before around advice");
    pjp.proceed();
    System.out.println("after around advice");
}

pjp.proceed()方法表示目標對象中要增加的方法,即爲連接點方法

pjp常用方法:

getArgs():返回方法參數

getThis():返回代理對象

getTarget():返回目標對像`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章