1. 程式人生 > >Spring Boot Spring Aop初接觸

Spring Boot Spring Aop初接觸

眾所周知,spring最核心的兩個功能是aop和ioc,即面向切面,控制反轉。這裡我們探討一下如何使用spring aop。

1.何為aop

  aop全稱Aspect Oriented Programming,面向切面,AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。其與設計模式完成的任務差不多,是提供另一種角度來思考程式的結構,來彌補面向物件程式設計的不足。

  通俗點講就是提供一個為一個業務實現提供切面注入的機制,通過這種方式,在業務執行中將定義好的切面通過切入點繫結到業務中,以實現將一些特殊的邏輯繫結到此業務中。

  比如,若是需要一個記錄日誌的功能,首先想到的是在方法中通過log4j或其他框架來進行記錄日誌,但寫下來發現一個問題,在整個業務中其實核心的業務程式碼並沒有多少,都是一些記錄日誌或其他輔助性的一些程式碼。而且很多業務有需要相同的功能,比如都需要記錄日誌,這時候又需要將這些記錄日誌的功能複製一遍,即使是封裝成框架,也是需要呼叫之類的。在此處使用複雜的設計模式又得不償失。

  所以就需要面向切面出場了。

3.搭建aop

  本來spring就自帶一套aop實現,我們直接使用此實現即可,本來使用aop還需要定義一些xml檔案,但由於我們使用的是spring-boot框架,這一步就省略掉了。也就是說,在spring-boot中,我們可以直接使用aop而不需要任何的配置

4.aop名稱

  先介紹一些aop的名詞,其實這些名詞對使用aop沒什麼影響,但為了更好的理解最好知道一些

  • 切面(Aspect):一個關注點的模組化,這個關注點可能會橫切多個物件。事務管理是J2EE應用中一個關於橫切關注點的很好的例子。在Spring AOP中,切面可以使用基於模式或者基於@Aspect註解的方式來實現。

  • 連線點(Joinpoint):在程式執行過程中某個特定的點,比如某方法呼叫的時候或者處理異常的時候。在Spring AOP中,一個連線點總是表示一個方法的執行。

  • 通知(Advice):在切面的某個特定的連線點上執行的動作。其中包括了“around”、“before”和“after”等不同型別的通知(通知的型別將在後面部分進行討論)。許多AOP框架(包括Spring)都是以攔截器

    做通知模型,並維護一個以連線點為中心的攔截器鏈。

  • 切入點(Pointcut):匹配連線點的斷言。通知和一個切入點表示式關聯,並在滿足這個切入點的連線點上執行(例如,當執行某個特定名稱的方法時)。切入點表示式如何和連線點匹配是AOP的核心:Spring預設使用AspectJ切入點語法。

  • 引入(Introduction):用來給一個型別宣告額外的方法或屬性(也被稱為連線型別宣告(inter-type declaration))。Spring允許引入新的介面(以及一個對應的實現)到任何被代理的物件。例如,你可以使用引入來使一個bean實現IsModified介面,以便簡化快取機制。

  • 目標物件(Target Object):被一個或者多個切面所通知的物件。也被稱做被通知(advised)物件。既然Spring AOP是通過執行時代理實現的,這個物件永遠是一個被代理(proxied)物件。

  • AOP代理(AOP Proxy):AOP框架建立的物件,用來實現切面契約(例如通知方法執行等等)。在Spring中,AOP代理可以是JDK動態代理或者CGLIB代理。

  • 織入(Weaving):把切面連線到其它的應用程式型別或者物件上,並建立一個被通知的物件。這些可以在編譯時(例如使用AspectJ編譯器),類載入時和執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。

       其中重要的名詞有:切面,切入點

 5.簡單例子:

    可能直接說會很模糊,這裡我先做了一個小例子:直接上程式碼

複製程式碼
//描述切面類
@Aspect
@Configuration
public class TestAop {

    /*
     * 定義一個切入點
     */
    // @Pointcut("execution (* findById*(..))")
    @Pointcut("execution(* com.test.service.CacheDemoService.find*(..))")
    public void excudeService(){}
    /*
     * 通過連線點切入
     */
    @Before("execution(* findById*(..)) &&" + "args(id,..)")
    public void twiceAsOld1(Long id){
        System.err.println ("切面before執行了。。。。id==" + id);

    }

    @Around("excudeService()")
    public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint){
        System.err.println ("切面執行了。。。。");
        try {
            Thing thing = (Thing) thisJoinPoint.proceed ();
            thing.setName (thing.getName () + "=========");
            return thing;
        } catch (Throwable e) {
            e.printStackTrace ();
        }
        return null;
    }

}
複製程式碼

  看上面的例子就是實現了一個切面,其中有一些特殊的東西,下面一一解釋:

6.使用的註解:

   @Aspect:描述一個切面類,定義切面類的時候需要打上這個註解

   @Configuration:spring-boot配置類

   1. @Pointcut:宣告一個切入點,切入點決定了連線點關注的內容,使得我們可以控制通知什麼時候執行。Spring AOP只支援Spring bean的方法執行連線點。所以你可以把切入點看做是Spring bean上方法執行的匹配。一個切入點宣告有兩個部分:一個包含名字和任意引數的簽名,還有一個切入點表示式,該表示式決定了我們關注那個方法的執行。

  注:作為切入點簽名的方法必須返回void 型別

  Spring AOP支援在切入點表示式中使用如下的切入點指示符:    

    • execution - 匹配方法執行的連線點,這是你將會用到的Spring的最主要的切入點指示符。

    • within - 限定匹配特定型別的連線點(在使用Spring AOP的時候,在匹配的型別中定義的方法的執行)。

    • this - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中bean reference(Spring AOP 代理)是指定型別的例項。

    • target - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中目標物件(被代理的應用物件)是指定型別的例項。

    • args - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中引數是指定型別的例項。

    • @target - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中正執行物件的類持有指定型別的註解。

    • @args - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中實際傳入引數的執行時型別持有指定型別的註解。

    • @within - 限定匹配特定的連線點,其中連線點所在型別已指定註解(在使用Spring AOP的時候,所執行的方法所在型別已指定註解)。

    • @annotation - 限定匹配特定的連線點(使用Spring AOP的時候方法的執行),其中連線點的主題持有指定的註解。

         其中execution使用最頻繁,即某方法執行時進行切入。定義切入點中有一個重要的知識,即切入點表示式,我們一會在解釋怎麼寫切入點表示式。

   切入點意思就是在什麼時候切入什麼方法,定義一個切入點就相當於定義了一個“變數”,具體什麼時間使用這個變數就需要一個通知。

   即將切面與目標物件連線起來。

  如例子中所示,通知均可以通過註解進行定義,註解中的引數為切入點。

  spring aop支援的通知:

  @Before:前置通知:在某連線點之前執行的通知,但這個通知不能阻止連線點之前的執行流程(除非它丟擲一個異常)。

  @AfterReturning:後置通知:在某連線點正常完成後執行的通知,通常在一個匹配的方法返回的時候執行。

      可以在後置通知中繫結返回值,如:        

複製程式碼
@AfterReturning(
    pointcut=com.test.service.CacheDemoService.findById(..))",
    returning="retVal"public void doFindByIdCheck(Object retVal) {
    // ...
  }
複製程式碼

   @AfterThrowing:異常通知:在方法丟擲異常退出時執行的通知。       

   @After 最終通知。當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)

   @Around:環繞通知:包圍一個連線點的通知,如方法呼叫。這是最強大的一種通知型別。環繞通知可以在方法呼叫前後完成自定義的行為。它也會選擇是否繼續執行連線點或直接返回它自己的返回值或丟擲異常來結束執行。

環繞通知最麻煩,也最強大,其是一個對方法的環繞,具體方法會通過代理傳遞到切面中去,切面中可選擇執行方法與否,執行方法幾次等。

      環繞通知使用一個代理ProceedingJoinPoint型別的物件來管理目標物件,所以此通知的第一個引數必須是ProceedingJoinPoint型別,在通知體內,呼叫ProceedingJoinPointproceed()方法會導致後臺的連線點方法執行。proceed 方法也可能會被呼叫並且傳入一個Object[]物件-該陣列中的值將被作為方法執行時的引數。

7.通知引數

  任何通知方法可以將第一個引數定義為org.aspectj.lang.JoinPoint型別(環繞通知需要定義第一個引數為ProceedingJoinPoint型別,它是 JoinPoint 的一個子類)。JoinPoint介面提供了一系列有用的方法,比如 getArgs()(返回方法引數)、getThis()(返回代理物件)、getTarget()(返回目標)、getSignature()(返回正在被通知的方法相關資訊)和 toString()(打印出正在被通知的方法的有用資訊)

  有時候我們定義切面的時候,切面中需要使用到目標物件的某個引數,如何使切面能得到目標物件的引數。

  從例子中可以看出一個方法:

  使用args來繫結。如果在一個args表示式中應該使用型別名字的地方 使用一個引數名字,那麼當通知執行的時候對應的引數值將會被傳遞進來。

 @Before("execution(* findById*(..)) &&" + "args(id,..)")
    public void twiceAsOld1(Long id){
        System.err.println ("切面before執行了。。。。id==" + id);

    }
複製程式碼
@Around("execution(List<Account> find*(..)) &&" +
        "com.xyz.myapp.SystemArchitecture.inDataAccessLayer() && " +
        "args(accountHolderNamePattern)"public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)
throws Throwable {
  String newPattern = preProcess(accountHolderNamePattern);
  return pjp.proceed(new Object[] {newPattern});
}        
複製程式碼

8.切入點表示式

  現在我們介紹一下最重要的切入點表示式:

  如上文所說,定義切入點時需要一個包含名字和任意引數的簽名,還有一個切入點表示式,就是* findById*(..)這一部分。

  切入點表示式的格式:execution([可見性] 返回型別 [宣告型別].方法名(引數) [異常])

  其中【】中的為可選,其他的還支援萬用字元的使用:

    *:匹配所有字元
      ..:一般用於匹配多個包,多個引數
      +:表示類及其子類

  運算子有:&&、||、!

切入點表示式關鍵詞:   

    1)execution:用於匹配子表示式。

            //匹配com.cjm.model包及其子包中所有類中的所有方法,返回型別任意,方法引數任意
            @Pointcut("execution(* com.cjm.model..*.*(..))")
            public void before(){}

      2)within:用於匹配連線點所在的Java類或者包。

            //匹配Person類中的所有方法
            @Pointcut("within(com.cjm.model.Person)")
            public void before(){}

            //匹配com.cjm包及其子包中所有類中的所有方法

            @Pointcut("within(com.cjm..*)")
            public void before(){}

     3) this:用於向通知方法中傳入代理物件的引用。
            @Before("before() && this(proxy)")
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //處理邏輯
            }

      4)target:用於向通知方法中傳入目標物件的引用。
            @Before("before() && target(target)
            public void beforeAdvide(JoinPoint point, Object proxy){
                  //處理邏輯
            }

      5)args:用於將引數傳入到通知方法中。
            @Before("before() && args(age,username)")
            public void beforeAdvide(JoinPoint point, int age, String username){
                  //處理邏輯
            }
 
      6)@within :用於匹配在類一級使用了引數確定的註解的類,其所有方法都將被匹配。 

            @Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation標註的類都將匹配
            public void before(){}

     7)@target :和@within的功能類似,但必須要指定註解介面的保留策略為RUNTIME。
            @Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}

      8)@args :傳入連線點的物件對應的Java類必須被@args指定的Annotation註解標註。
            @Before("@args(com.cjm.annotation.AdviceAnnotation)")
            public void beforeAdvide(JoinPoint point){
                  //處理邏輯
            }

      9)@annotation :匹配連線點被它引數指定的Annotation註解的方法。也就是說,所有被指定註解標註的方法都將匹配。
            @Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
            public void before(){}

      10)bean:通過受管Bean的名字來限定連線點所在的Bean。該關鍵詞是Spring2.5新增的。
            @Pointcut("bean(person)")
            public void before(){}


 9.參考資料

    http://blog.csdn.net/yuqinying112/article/details/7244281

    http://www.2cto.com/kf/201204/128280.html

    http://blog.csdn.net/archie2010/article/details/6254343

相關推薦

Spring Boot Spring Aop接觸

眾所周知,spring最核心的兩個功能是aop和ioc,即面向切面,控制反轉。這裡我們探討一下如何使用spring aop。 1.何為aop   aop全稱Aspect Oriented Programming,面向切面,AOP主要實現的目的是針對業務處理過程中的切面

Spring Boot學習——AOP編程的簡單實現

col .com tsig 訪問 pan -s ping 編程範式 lan 首先應該明白一點,AOP是一種編程範式,是一種程序設計思想,與具體的計算機編程語言無關,所以不止是Java,像.Net等其他編程語言也有AOP的實現方式。AOP的思想理念就是將通用邏輯

Spring Bootaop中獲取request對象

stat class gpo thold t對象 對象 pat ring before doBefore(){ ServetRequestAttrbtes attributes = (ServetRequestAttrbtes)RequestContextHolder.

Spring Boot 應用AOP

通知 匹配 ide CA AS 結束 RR 依賴 表示 # Spring Boot 應用AOP 一、在pom中添加依賴 <dependency> <groupId>org.springframework.boot</groupId>

Spring Boot使用AOP實現攔截某個方法

ces 文件 commit ransac dex red code join info 1、引入.jarl文件依賴 <!-- Spring Boot Web 依賴 --> <dependency>

Spring Boot使用AOP實現REST接口簡易靈活的安全認證

all 高級 mes 之前 接口 封裝 msg mage ror 本文將通過AOP的方式實現一個相對更加簡易靈活的API安全認證服務。 我們先看實現,然後介紹和分析AOP基本原理和常用術語。 一、Authorized實現1、定義註解 package com.power.de

Spring Boot使用AOP搭建統一處理請求日誌和使用log4j記錄不同級別的日誌

受http://blog.didispace.com/springbootaoplog/啟發,今天給Spring Boot專案搭建了統一處理請求日誌的切面並引入log4j記錄不同層級日誌。 mark一下這個過程,以及原文中沒有涉及到的一些疑問 一.  新增要使用的依賴&nbs

spring mvc和spring boot實現AOP

spring boot實現AOP 首先建立切面類需要@Aspect,@Component註解 然後建立@Pointcut確定什麼方法實現aop @Pointcut("execution(* com.air_baocl.controller.selectApi.*(..))")

Spring Boot系列——AOP配自定義註解的最佳實踐

AOP(Aspect Oriented Programming),即面向切面程式設計,是Spring框架的大殺器之一。 首先,我宣告下,我不是來系統介紹什麼是AOP,更不是照本宣科講解什麼是連線點、切面、通知和切入點這些讓人頭皮發麻的概念。 今天就來說說AOP的一些應用場景以及如何通過和其他特性的結合提升

Spring-boot 配置Aop獲取controller裡的request中的引數以及其返回值

轉自:http://ysj5125094.iteye.com/blog/2151855 前提條件: 除了spring相關jar包外,還需要引入aspectj包。 Xml程式碼  <dependency>     

spring boot實現AOP登入攔截

1.在pom.xml中新增配置 <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifac

Spring boot 結合aop,自定義註解,切面的理解

package com.imooc.boot.controller; import com.imooc.boot.aspect.IndexAspect; import org.springframework.web.bind.annotation.RequestMapping; import

Spring BootAOP統一處理HTTP請求

版權宣告:博主原創/資料整理,轉載請註明出處!! 首先,AOP (Aspect Oriented Programming )指面向切面程式設計,通過預編譯方式或者執行時刻對目標物件動態地新增功能。 一、Spring Boot中新增AOP依賴 <

Spring Boot 使用AOP記錄操作日誌

前言 在寫Aurora這個專案之前,我是通過攔截器去記錄使用者操作日誌,而這裡講解如何使用AOP配合自定義註解去實現使用者日誌記錄,使用攔截器的方式,下一章貼出 匯入依賴 <!-- aop依賴 --> <dependency> &

Spring BootAOP面向切面程式設計-實戰篇

目錄 前言 程式設計正規化主要有以下幾類 引入pom依賴 aop註解 實現日誌分割功能 前言 AOP是一種與語言無關的程式思想、程式設計正規化。專案業務邏輯中,將通用的模組以水平切割的方式進行分離統一處理,常用於日誌、許可權控制、異常處理等業務中。 程式設計正規化主

spring-boot使用AOP統一處理日誌

轉載地址:https://blog.csdn.net/w05980598/article/details/79053209 AOP我想大家都很清楚,有時候我們需要處理一些請求日誌,或者對某些方法進行一些監控,如果出現例外情況應該進行怎麼樣的處理,現在,我們從spring boot中引入

spring boot使用aop攔截Controller和Service以方便除錯

除錯的時候,經常需要看每個函式的輸入輸出,以前每次都是System.out.println輸出,除錯完後還要刪掉,要是每次都能自己輸出函式的輸入輸出就好了。 在網上找了一通,結合《Spring 實戰》寫了一個自己用的切面 BaseAspect public abst

Spring boot 通過AOP獲取引數名稱及引數值並對引數進行校驗

/** * 定義切入點為 帶有 NotEnableEmpty 註解的 */ @Pointcut("@annotation(cn.acsm.paddy.manage.anotation.NotEnableEmpty)") public void params() { }

Spring boot(20) Spring /Spring boot使用AOP、強制使用cglib(以記錄方法耗時為例子)

1. Spring boot 1.1 Spring boot預設使用了AOP和動態代理 RPC,AOP都會用到代理,代理的技術有jdk的Proxy代理(必須傳入介面),cglib(可以是類而非介面, spring),Javassist(jboss )而S

Spring Boot 整合AOP

在這裡多談一些關於AOP 方面的知識,如果你對AOP 方面的知識比較熟悉,可以直接略過這個段落,往下看。 一、AOP概述 AOP(面向切面程式設計) 概念:這種在執行時,動態地將程式碼切入到類的指定方法、指定位置上的程式設計思想就是面向切面的程式設計。