最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?AOP通知類型與實戰(zhàn)示例講解

 更新時間:2024年11月18日 12:14:59   作者:lzz的編碼時刻  
Spring?AOP提供了五種通知類型:@Before、@After、@AfterReturning、@AfterThrowing和@Around,每種通知類型都有其特定的使用場景和實現(xiàn)方式,通過合理使用這些通知類型,可以實現(xiàn)各種橫切關注點的模塊化和解耦,感興趣的朋友跟隨小編一起看看吧

1. @Before 前置通知

1.1 基本說明

  • 在目標方法執(zhí)行前執(zhí)行
  • 不能阻止目標方法執(zhí)行(除非拋出異常)
  • 可以獲取目標方法的參數(shù)信息

1.2 實現(xiàn)示例

@Aspect
@Component
public class SecurityAspect {
    @Before("@annotation(requiresAuth)")
    public void checkAuth(JoinPoint joinPoint, RequiresAuth requiresAuth) {
        // 獲取當前用戶信息
        ServletRequestAttributes attributes = 
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("Authorization");
        // 驗證token
        if (!tokenService.isValid(token)) {
            throw new UnauthorizedException("無效的認證令牌");
        }
        // 檢查權限
        String requiredRole = requiresAuth.role();
        if (!hasRole(token, requiredRole)) {
            throw new ForbiddenException("權限不足");
        }
    }
}

1.3 典型應用場景

  • 權限驗證
  • 參數(shù)驗證
  • 日志記錄
  • 事務開始標記
  • 緩存預處理

1.4 獲取參數(shù)

1.4.1 基本參數(shù)獲取

@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
    // 獲取方法參數(shù)
    Object[] args = joinPoint.getArgs();
    // 獲取方法簽名
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getName();
    // 獲取參數(shù)名稱
    String[] parameterNames = signature.getParameterNames();
    // 獲取參數(shù)類型
    Class<?>[] parameterTypes = signature.getParameterTypes();
    // 打印參數(shù)信息
    for (int i = 0; i < args.length; i++) {
        logger.info("Parameter {} ({}) = {}", parameterNames[i], parameterTypes[i].getSimpleName(), args[i]);
    }
}

1.4.2 獲取注解參數(shù)

@Before("@annotation(logParams)")
public void beforeWithAnnotation(JoinPoint joinPoint, LogParams logParams) {
    // 直接獲取注解屬性
    String description = logParams.description();
    boolean logResult = logParams.logResult();
    // 獲取方法參數(shù)
    Object[] args = joinPoint.getArgs();
    // 根據(jù)注解配置記錄日志
    if (logParams.includeParameters()) {
        Arrays.stream(args)
              .forEach(arg -> logger.info("Parameter value: {}", arg));
    }
}

2. @After 后置通知

2.1 基本說明

  • 在目標方法執(zhí)行后執(zhí)行(無論是否拋出異常)
  • 不能訪問目標方法的返回值
  • 主要用于清理資源或類似的收尾工作

2.2 實現(xiàn)示例

@Aspect
@Component
public class ResourceCleanupAspect {
    @After("execution(* com.example.service.FileService.*(..))")
    public void cleanup(JoinPoint joinPoint) {
        try {
            // 清理臨時文件
            String methodName = joinPoint.getSignature().getName();
            logger.info("Cleaning up resources after method: {}", methodName);
            cleanupTempFiles();
            // 釋放其他資源
            releaseResources();
        } catch (Exception e) {
            logger.error("Cleanup failed", e);
        }
    }
    private void cleanupTempFiles() {
        // 清理臨時文件的具體實現(xiàn)
    }
    private void releaseResources() {
        // 釋放資源的具體實現(xiàn)
    }
}

2.3 典型應用場景

  • 資源清理
  • 連接關閉
  • 計數(shù)器更新
  • 日志記錄
  • 性能監(jiān)控結束標記

2.4 參數(shù)獲取

@After("execution(* com.example.service.*.*(..)) && args(id,name,..)")
public void afterAdvice(JoinPoint joinPoint, Long id, String name) {
    // 直接使用參數(shù)
    logger.info("Method executed with ID: {} and name: {}", id, name);
    // 獲取目標類信息
    Class<?> targetClass = joinPoint.getTarget().getClass();
    // 獲取代理類信息
    Class<?> proxyClass = joinPoint.getThis().getClass();
}

3. @AfterReturning 返回通知

3.1 基本說明

  • 在目標方法成功執(zhí)行后執(zhí)行
  • 可以訪問目標方法的返回值
  • 可以修改返回值(通過包裝類)

3.2 實現(xiàn)示例

@Aspect
@Component
public class ResponseHandlerAspect {
    @AfterReturning(
        pointcut = "execution(* com.example.controller.*.*(..))",
        returning = "result"
    )
    public void handleResponse(JoinPoint joinPoint, Object result) {
        if (result instanceof List) {
            // 對集合類型結果進行脫敏處理
            List<?> list = (List<?>) result;
            for (Object item : list) {
                if (item instanceof UserDTO) {
                    UserDTO user = (UserDTO) item;
                    user.setPhone(maskPhoneNumber(user.getPhone()));
                    user.setEmail(maskEmail(user.getEmail()));
                }
            }
        }
    }
    private String maskPhoneNumber(String phone) {
        // 手機號碼脫敏邏輯
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }
    private String maskEmail(String email) {
        // 郵箱脫敏邏輯
        return email.replaceAll("(\\w{3})\\w+(@\\w+\\.\\w+)", "$1***$2");
    }
}

3.3 典型應用場景

  • 返回值修改(如數(shù)據(jù)脫敏)
  • 統(tǒng)計方法成功率
  • 緩存結果
  • 結果格式化
  • 數(shù)據(jù)集合包裝

4. @AfterThrowing 異常通知

4.1 基本說明

  • 在目標方法拋出異常時執(zhí)行
  • 可以訪問拋出的異常信息
  • 可以進行異常轉換或處理

4.2 實現(xiàn)示例

@Aspect
@Component
public class ExceptionHandlerAspect {
    @AfterThrowing(
        pointcut = "execution(* com.example.service.*.*(..))",
        throwing = "ex"
    )
    public void handleException(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();
        // 記錄詳細錯誤信息
        logger.error("Exception in {}.{}: {}", className, methodName, ex.getMessage());
        // 發(fā)送告警
        if (ex instanceof DataAccessException) {
            alertService.sendDatabaseAlert(className, methodName, ex);
        }
        // 異常分類統(tǒng)計
        metricService.incrementExceptionCounter(className, methodName, ex.getClass().getSimpleName());
        // 如果需要,可以轉換異常類型
        if (ex instanceof SQLException) {
            throw new DatabaseException("數(shù)據(jù)庫操作失敗", ex);
        }
    }
}

4.3 典型應用場景

  • 異常記錄
  • 異常轉換
  • 告警通知
  • 失敗重試
  • 錯誤統(tǒng)計

5. @Around 環(huán)繞通知

5.1 基本說明

  • 最強大的通知類型,可以完全控制目標方法的執(zhí)行
  • 可以在方法執(zhí)行前后添加自定義行為
  • 可以修改方法的參數(shù)和返回值
  • 可以決定是否執(zhí)行目標方法

5.2 實現(xiàn)示例

@Aspect
@Component
public class CacheAspect {
    @Autowired
    private CacheManager cacheManager;
    @Around("@annotation(cacheable)")
    public Object handleCache(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {
        // 構建緩存key
        String key = buildCacheKey(joinPoint, cacheable);
        // 嘗試從緩存獲取
        Object cachedValue = cacheManager.get(key);
        if (cachedValue != null) {
            logger.debug("Cache hit for key: {}", key);
            return cachedValue;
        }
        // 執(zhí)行目標方法
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
            // 記錄執(zhí)行時間
            long executionTime = System.currentTimeMillis() - startTime;
            logger.debug("Method execution time: {}ms", executionTime);
            // 如果執(zhí)行時間超過閾值,發(fā)送告警
            if (executionTime > 1000) {
                alertService.sendPerformanceAlert(joinPoint, executionTime);
            }
        } catch (Exception e) {
            // 異常處理
            logger.error("Method execution failed", e);
            throw e;
        }
        // 將結果放入緩存
        if (result != null) {
            cacheManager.put(key, result, cacheable.ttl());
        }
        return result;
    }
    private String buildCacheKey(ProceedingJoinPoint joinPoint, Cacheable cacheable) {
        // 緩存key構建邏輯
        StringBuilder key = new StringBuilder();
        key.append(joinPoint.getSignature().getDeclaringTypeName())
           .append(".")
           .append(joinPoint.getSignature().getName());
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            key.append(":");
            for (Object arg : args) {
                key.append(arg != null ? arg.toString() : "null").append(",");
            }
        }
        return key.toString();
    }
}

5.3 典型應用場景

  • 方法緩存
  • 性能監(jiān)控
  • 事務處理
  • 重試機制
  • 并發(fā)控制
  • 限流處理
@Aspect
@Component
public class RateLimiterAspect {
    private final RateLimiter rateLimiter = RateLimiter.create(100.0); // 每秒100個請求
    @Around("@annotation(rateLimited)")
    public Object limitRate(ProceedingJoinPoint joinPoint, RateLimited rateLimited) throws Throwable {
        if (!rateLimiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
            throw new TooManyRequestsException("請求過于頻繁,請稍后重試");
        }
        return joinPoint.proceed();
    }
}

6. 最佳實踐

  • 選擇合適的通知類型
    • 如果只需要前置處理,用@Before
    • 如果需要訪問返回值,用@AfterReturning
    • 如果需要處理異常,用@AfterThrowing
    • 如果需要完全控制方法執(zhí)行,用@Around
  • 性能考慮

    • 避免在通知中執(zhí)行耗時操作
    • 合理使用緩存
    • 注意異常處理的性能影響
  • 代碼組織

    • 每個切面專注于單一職責
    • 通知方法保持簡潔
    • 復用共同的切入點表達式
  • 異常處理

    • 在通知中要做好異常處理
    • 不要吞掉異常
    • 適當轉換異常類型

到此這篇關于Spring AOP通知類型詳解與實戰(zhàn)的文章就介紹到這了,更多相關Spring AOP通知類型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 關于SpringBoot在有Ajax時候不跳轉的問題解決

    關于SpringBoot在有Ajax時候不跳轉的問題解決

    最近在使用Ajax來發(fā)送一些數(shù)據(jù)給后臺一個Controller,但是遇到些問題,所以下面這篇文章主要給大家介紹了關于SpringBoot在有Ajax時候不跳轉問題的解決辦法,需要的朋友可以參考下
    2022-05-05
  • IDEA MyBatis Plugins自動生成實體類和mapper.xml

    IDEA MyBatis Plugins自動生成實體類和mapper.xml

    這篇文章主要介紹了IDEA MyBatis Plugins自動生成實體類和mapper.xml,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • SpringBoot整合Mybatis實現(xiàn)CRUD

    SpringBoot整合Mybatis實現(xiàn)CRUD

    這篇文章主要介紹了SpringBoot整合Mybatis實現(xiàn)CRUD的相關知識,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • 詳細總結IDEA中打jar包的兩種方式

    詳細總結IDEA中打jar包的兩種方式

    發(fā)現(xiàn)有很多小伙伴都不會用IDEA打jar包,今天給大家詳細總結了兩種IDEA打jar包的方式,對正在學習IDEA使用的小伙伴很有幫助,需要的朋友可以參考下
    2021-05-05
  • 阿里巴巴 Sentinel + InfluxDB + Chronograf 實現(xiàn)監(jiān)控大屏

    阿里巴巴 Sentinel + InfluxDB + Chronograf 實現(xiàn)監(jiān)控大屏

    這篇文章主要介紹了阿里巴巴 Sentinel + InfluxDB + Chronograf 實現(xiàn)監(jiān)控大屏,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • java 中Object與Objects的區(qū)別在哪里

    java 中Object與Objects的區(qū)別在哪里

    這篇文章主要介紹了java 中Object與Objects的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • Java多線程中Lock鎖的使用小結

    Java多線程中Lock鎖的使用小結

    這篇文章主要介紹了Java多線程中Lock鎖的使用小結,本節(jié)主要講了它的基本使用,大家可以舉一反三,試試什么條件下會導致死鎖,需要的朋友可以參考下
    2022-06-06
  • java實現(xiàn)自動回復聊天機器人

    java實現(xiàn)自動回復聊天機器人

    這篇文章主要為大家詳細介紹了java實現(xiàn)自動回復聊天機器人,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Java并發(fā)中死鎖、活鎖和饑餓是什么意思

    Java并發(fā)中死鎖、活鎖和饑餓是什么意思

    今天看到的一篇文章,說的很好,再敲了一遍,分享一下有關于死鎖、活鎖及饑餓的概念和區(qū)別,感興趣的可以了解一下
    2021-11-11
  • Maven在Windows中的配置以及IDE中的項目創(chuàng)建實例

    Maven在Windows中的配置以及IDE中的項目創(chuàng)建實例

    下面小編就為大家?guī)硪黄狹aven在Windows中的配置以及IDE中的項目創(chuàng)建實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09

最新評論

巍山| 常州市| 多伦县| 黔西县| 临猗县| 满洲里市| 文水县| 镶黄旗| 泽普县| 亚东县| 奉化市| 明星| 龙江县| 伽师县| 安仁县| 英山县| 武汉市| 德清县| 西青区| 建始县| 兰西县| 玉田县| 蕲春县| 波密县| 本溪市| 内黄县| 米脂县| 衡山县| 宜兰市| 光山县| 天津市| 方正县| 威信县| 句容市| 衡阳县| 惠州市| 紫阳县| 常山县| 潼南县| 弥勒县| 兴业县|