【開發必備】Spring AOP的靈活運用

轉載請聲明出處!安全

Spring AOP爲咱們提供了一種更簡潔的代碼編寫方法。主要用來隔離業務邏輯代碼,下降非業務代碼的侵入性。好比像日誌記錄,安全管理,事務管理等,若是直接寫到業務代碼裏,侵入性大,代碼閱讀性差。bash

若是你的項目使用了AOP,那麼能夠給你的類裏的方法添加更多功能,讓代碼更簡潔易讀。app

在這裏,James不打算和你們討論AOP的基礎知識。若是沒有用過AOP的同窗,能夠先百度簡單看一下AOP的基本概念,咱們將主要關注Spring AOP應用程序。性能

在咱們開發的任何應用程序中,如下的這些代碼我相信必定是你們都寫過的:ui

//服務層
@Service
public class OrderServiceImpl {
    public Order queryOrder() {
        System.out.println("Reading from collectionA");
        return new Order("1","2019-07-11");
    }

    public int updateOrder() {
        System.out.println("Writing to collectionA");
        return 1;
    }
}
//控制層
@Controller
public class OrderController {
    @Autowired
    OrderServiceImpl orderServiceImpl;

    //訂單查詢
    @RequestMapping("query")
    public Order queryOrder() {
        return orderServiceImpl.queryOrder();
    }
    //訂單修改
    @RequestMapping("update")
    public int updateOrder() {
         return orderServiceImpl.updateOrder();
     }
}
複製代碼

在上面的示例中,咱們在控制層中有一個OrderController類和一個OrderServiceImpl業務類。spa

若是如今有這麼一個需求:日誌

在咱們的應用程序的第一個版本中,它是沒有受權功能,如今的需求是要加一個受權功能。code

在上面的示例中,在咱們操做訂單信息以前(不論是查詢仍是修改)添加一個檢查用戶是否爲admin的功能。orm

實現此功能的一種方法是建立Authorization類和isAuthorized方法來檢查用戶是否被受權。那麼咱們須要更新OrderServiceImpl的全部方法,並經過調用isAuthorized方法來檢查受權。對象

@Component
public class OrderServiceImpl {
     public Order queryOrder() {
         //判斷當前登錄用戶是否有權限查詢
         if (Authorization.isAuthorised(Session.getUserId())){
             System.out.println("Reading from collectionA");
             return new Order("1","2019-07-11");
         }
     }
    public int updateOrder() {
         //判斷當前登錄用戶是否有權限修改
         if (Authorization.isAuthorised(Session.getUserId())){
             System.out.println("Writing to collectionA");
             return 1;
         }
     }
}
複製代碼

可是,這種方法存在缺點。咱們須要修改OrderServiceImpl類的每一個方法,而且在全部方法中重複調用isAuthorized方法的相同代碼以檢查受權。

若是不更改現有類,能不能完成受權檢查功能呢?

固然能夠,AOP就能夠實現。

如今定義一個AuthorizationCheck類,能夠爲OrderServiceImpl類建立一個切入點。在建議中,咱們檢查用戶是不是管理員,而後咱們繼續;不然,咱們不操做。

無需在OrderServiceImpl類中進行任何更改。

代碼以下:

@Aspect
@Configuration
public class AuthorizationCheck {
     //使用Around切面攔截OrderServiceImpl類的全部方法,在調用OrderServiceImpl方法時自動檢查權限
     @Around("execution(**com.enjoy.aop.OrderServiceImpl.*(..))")
     public void check (ProceedingJoinPoint jp) {
          try {
               if(Authorization.isAuthorised(Session.getUserId())) {
                     jp.proceed();//手動執行目標方法,至關於調用OrderServiceImpl的某個方法
               }
               else {
                     System.out.println("User not Authorised");
               }
          } catch (Throwable e) {
                    e.printStackTrace();
          }
     }
}
複製代碼

如今,對於對OrderServiceImpl類的任何方法的任何調用,只有在知足時纔會調用訂單相關方法。

以上可見,在不更改現有類的狀況下,咱們完成了受權功能。固然除了這種使用方式外,咱們還能夠監控性能,好比監控OrderServiceImpl類裏方法執行的時間狀況,如何操做呢?見下

建立一個名爲TurnAroundTime自定義註解,用來檢查目標方法執行的性能與時間。

如下是一個例子:首先,咱們須要自定義一個註解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public@interface TurnAroundTime {
}
複製代碼

咱們想檢查的對象爲方法,因此這裏的目標類型是Method,@Target(ElementType.METHOD)。

RetentionPolicy是運行時,由於咱們想在運行時應用它們。接下來,咱們定義切面。

@Aspect
@Configuration
public class PerformanceCheck {
    //攔截com.enjoy.aop包下的全部方法,當方法聲明TurnAroundTime註解時,
    //都須要執行watchPerformance切面方法
     @Around("execution(** com.enjoy.aop.*.*.*(..))&& @annotation(TurnAroundTime)")
     public void watchPerformance(ProceedingJoinPoint jp) {
          Instant start = Instant.now();//調方法前計時
          try {
              jp.proceed();//手動執行目標方法,至關於調用OrderServiceImpl的某個方法
          } catch (Throwable e) {
              e.printStackTrace();
          }
          Instant finish = Instant.now();//調方法結束後計時
          long timeElapsed = Duration.between(start,finish).toMillis();//調用方法耗時多少
          System.out.println("Total Turnaround time:" + timeElapsed);
     }
}
複製代碼

咱們使用切入點定義一個切面,用該切面來監聽目標方法執行狀況。記錄目標方法執行前和執行以後的時間差。

所以,若咱們想要測量目標方法的性能時,咱們須要使用自定義註釋@TurnAroundTime來註釋該方法。

代碼以下:

@Component
public class OrderServiceImpl {
     @TurnAroundTime
     public Order queryOrder() {
          //判斷當前登錄用戶是否有權限查詢
         if (Authorization.isAuthorised(Session.getUserId())){
             System.out.println("Reading from collectionA");
             return new Order("1","2019-07-11");
         }
     }
    @TurnAroundTime
    public int updateOrder() {
         //判斷當前登錄用戶是否有權限修改
         if (Authorization.isAuthorised(Session.getUserId())){
             System.out.println("Writing to collectionA");
             return 1;
         }
     }
}
複製代碼

你們能夠看到,SpringAOP玩熟悉後,能夠解決不少代碼冗餘問題,方便咱們開發,自定義註解能讓咱們更好的美化代碼,減小代碼的侵入性,本節就寫到這裏吧。

你的贊和關注是我繼續創做的動力~

相關文章
相關標籤/搜索