SpringBoot切面編程
眾所周知,spring最核心的兩個功能是aop和ioc,即面向切面和控制反轉。本文會講一講SpringBoot如何使用AOP實現面向切面的過程原理。
何為AOP
AOP(Aspect OrientedProgramming):面向切面編程,面向切面編程(也叫面向方面編程),是目前軟件開發中的一個熱點,也是Spring框架中的一個重要內容。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
利用AOP可以對我們邊緣業務進行隔離,降低無關業務邏輯耦合性。提高程序的可重用性,同時提高了開發的效率。一般用于日志記錄,性能統計,安全控制,權限管理,事務處理,異常處理,資源池管理
。使用場景
AOP的一些核心概念
概念 | 定義 | 作用 | 示例 |
---|---|---|---|
橫切關注點 | 多個模塊中共同涉及的功能,如日志、事務、權限等 | 分離通用功能,避免代碼冗余 | 所有Service方法都需要記錄執行時間 |
切面(Aspect) | 封裝橫切關注點的模塊,包含切入點和通知 | 將橫切邏輯集中管理 | 定義一個日志切面,統一處理日志記錄 |
連接點(Join Point) | 程序執行中的特定點,如方法調用、字段修改等 | 作為切面織入的候選位置 | 某個Service方法被調用時 |
切入點(Pointcut) | 定義切面作用的具體位置,通過表達式匹配連接點 | 精確控制切面影響的范圍 | 匹配所有以save 開頭的方法 |
通知(Advice) | 切面在連接點執行的操作,分為前置、后置、返回、異常、環繞通知 | 實現具體的橫切功能 | 在方法執行前記錄參數,執行后記錄返回值 |
織入(Weaving) | 將切面與目標對象連接并創建代理對象的過程 | 使切面邏輯在特定時機生效 | 編譯時織入(AspectJ)、運行時織入(Spring AOP) |
目標對象(Target) | 被切面包裹的對象 | 被增強的原始業務對象 | 實際的UserService類 |
代理對象(Proxy) | 織入切面后生成的對象 | 替代原始對象,執行時包含切面邏輯 | 通過JDK動態代理生成的UserService代理對象 |
代碼實現
這段代碼展示了AOP(面向切面編程)在權限校驗場景中的典型應用。通過自定義注解和環繞通知,實現了方法級別的權限攔截,避免了在每個業務方法中重復編寫權限校驗邏輯。
1. 自定義注解 @AuthCheck
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {String mustRole() default "";
}
- 作用:標記需要進行權限校驗的方法,并指定所需的角色(如
@AuthCheck(mustRole = "ADMIN")
)。 - 元注解:
@Target(ElementType.METHOD)
:注解僅可用于方法。@Retention(RetentionPolicy.RUNTIME)
:注解在運行時保留,以便反射獲取。
2. 切面類 AuthInterceptor
@Aspect
@Component
public class AuthInterceptor {@Resourceprivate UserService userService;@Around("@annotation(authCheck)")public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {// 1. 獲取注解中指定的必須角色String mustRole = authCheck.mustRole();// 2. 獲取當前登錄用戶HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();User loginUser = userService.getLoginUser(request);// 3. 權限校驗邏輯UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);if (mustRoleEnum == null) return joinPoint.proceed(); // 無需權限,放行UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());if (userRoleEnum == null) throw new BusinessException(ErrorCode.NO_AUTH_ERROR);// 管理員權限校驗if (mustRoleEnum == UserRoleEnum.ADMIN && userRoleEnum != UserRoleEnum.ADMIN) {throw new BusinessException(ErrorCode.NO_AUTH_ERROR);}// 校驗通過,執行原方法return joinPoint.proceed();}
}
- 關鍵元素:
@Aspect
:聲明該類為切面。@Component
:將切面注冊為Spring Bean。@Around("@annotation(authCheck)")
:- 環繞通知,攔截所有標記了
@AuthCheck
注解的方法。 authCheck
參數綁定當前方法上的@AuthCheck
注解實例。
- 環繞通知,攔截所有標記了
AOP思想的體現
1. 關注點分離
- 業務邏輯(如用戶服務)與權限校驗完全解耦。
- 權限校驗邏輯集中在切面中,無需在每個業務方法中重復編寫。
2. 聲明式編程
- 通過
@AuthCheck
注解在方法上聲明所需權限,簡潔直觀。 - 示例:
@AuthCheck(mustRole = "ADMIN") public void deleteUser(Long userId) {// 業務邏輯(無需關心權限校驗) }
3. 動態代理機制
- Spring AOP通過動態代理(JDK或CGLIB)在運行時生成代理對象。
- 代理對象在調用目標方法前后插入權限校驗邏輯:
調用代理方法 → 執行前置校驗 → 執行目標方法 → 執行后置邏輯
執行流程
- 方法調用:客戶端調用標記了
@AuthCheck
的方法。 - 代理攔截:Spring AOP攔截調用,執行
AuthInterceptor
的環繞通知。 - 權限校驗:
- 從注解獲取所需角色(如
ADMIN
)。 - 從當前請求獲取登錄用戶信息。
- 比較用戶角色與注解要求的角色。
- 從注解獲取所需角色(如
- 結果處理:
- 校驗通過:執行原方法。
- 校驗失敗:拋出
BusinessException
。