0%

AOP (Aspect-Oriented Programming)

常用於 authentication(使用服務前驗證身分)、record log(紀錄行為日誌)
=> 屬橫切面,與系統主要服務功能較無直接關係

基本介紹

  • 基於OOP:把橫切面邏輯封裝

  • 類似 Proxy Pattern

  • 集中處理非核心邏輯之需求

  • 一段話了解AOP

    抽離非核心之共用邏輯,於特定時機點(程式前/後),執行其他次要業務邏輯的程式,使核心邏輯不受切面邏輯影響

  • 為什麼使用AOP

    OOP是以侵入性方式對原程式碼加入額外程式 => 重複、關注點混淆且難以維護
    AOP可降低系統的耦合,增加程式的可擴充性

  • 專注職責,降低依賴


術語

  • Aspect

    A modularization of a concern that cuts across multiple classes. (打包好的模組)

  • Point Cut

    A predicate that matches join points. (切入點的定義
    )

  • Join Point

    A point during the execution of a program. (aspect 呼叫的時機點)

  • Advice

    Action taken by an aspect at a particular join point. (aspect 的實作)

  • Weaving

    Linking aspects with other application types or objects to create an advised object. (advice被應用至物件上之過程)


Diagram

aop-gif


Code Snippet

Ex1. OOP Method

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public class SettingService {
public Object saveSetting(String name) {
try {
saveNameToDb(name); // 主功能
recordLog(Level.INFO, "hello success.");
return ResponseEntity.ok();
} catch(Exception e) {
recordLog(Level.INFO, "hello fail.");
return ResponseEntity.badRequest();
}
}
}

Ex2. AOP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


public class SettingService {

@LogRecord(logInfo = "'Save' + #name ", level = "INFO")
public Object saveSetting(String name) {
try {
saveNameToDb(name); // 主功能
return ResponseEntity.ok();
} catch(Exception e) {
return ResponseEntity.badRequest();
}
}
}



  • AOP Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

@Aspect
@Component
public class LogAOP {

@Pointcut(value=“@annotation(logRecord)")
public void pointcut() {};

// 執行前
@Before(value = "pointcut()")
public void getLogInfoBefore(JoinPoint joinPoint) { // ... }

// 執行後正常回傳
@AfterReturning(value = "pointcut()", returning = "returnValue")
public void getLogInfoAfterReturning(JoinPoint joinPoint, Object returnValue) { // ... }

// 執行後
@After(value = "pointcut()")
public void getLogInfoAfter(JoinPoint joinPoint) { // ... }

// 包括執行前/後、回傳值
@Around(value = "pointcut()")
public Object getLogInfoAround(ProceedingJoinPoint pjp) { // ... }

// 執行出現異常
@AfterThrowing(value = "pointcut()“, throwing= “e" )
public void getLogInfoAfterThrowing(Exception e) { // ... }


}
  • Custom Annotation
1
2
3
4
5
6
7
8
9

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface LogRecord{

String title();
String logInfo();

}