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

詳解Spring中的AOP及AspectJ五大通知注解

 更新時間:2023年08月15日 11:05:28   作者:ycfxhsw  
這篇文章主要介紹了詳解Spring中的AOP及AspectJ五大通知注解,AOP面向切面編程是一種新的方法論,是對傳統(tǒng)OOP面向?qū)ο缶幊痰难a充,AOP?的主要編程對象是切面(aspect),切面模塊化橫切關注點,需要的朋友可以參考下

AOP 基本概念

AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論,是對傳統(tǒng) -OOP(Object-Oriented Programming, 面向?qū)ο缶幊? 的補充。

AOP 的主要編程對象是切面(aspect), 切面模塊化橫切關注點。

在應用 AOP 編程時, 仍然需要定義公共功能, 但可以明確的定義這個功能用在哪里,以什么方式應用,并且不必修改受影響的類,這樣一來橫切關注點就被模塊化到特殊的對象(切面)里。

AOP 的好處:

  • 每個事物邏輯位于一個位置,代碼不分散,便于維護和升級。
  • 業(yè)務模塊更簡潔,只包含核心業(yè)務代碼。

AOP術語

  • 切面(Aspect): 橫切關注點(跨越應用程序多個模塊的功能)被模塊化的特殊對象。
  • 通知(Advice): 切面必須要完成的工作。
  • 目標(Target): 被通知的對象
  • 代理(Proxy): 向目標對象應用通知之后創(chuàng)建的對象。
  • 連接點(Joinpoint):程序執(zhí)行的某個特定位置:如類某個方法調(diào)用前、調(diào)用后、方法拋出異常后等。連接點由兩個信息確定:方法表示的程序執(zhí)行點;相對點表示的方位。方位為方法執(zhí)行前的位置。
  • 切點(pointcut):每個類都擁有多個連接點:即連接點是程序類中客觀存在的事務AOP 通過切點定位到特定的連接點。類比:連接點相當于數(shù)據(jù)庫中的記錄,切點相當于查詢條件。切點和連接點不是一對一的關系,一個切點匹配多個連接點,切點通過 org.springframework.aop.Pointcut 接口進行描述,它使用類和方法作為連接點的查詢條件。

AspectJ

  • AspectJ:Java 社區(qū)里最完整最流行的 AOP 框架.
  • 在 Spring2.0 以上版本中,可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

應用

本文以一個簡單計算器為代碼例子

AOP

1、在Spring中啟用AspectJ 注解支持

  • 要在 Spring 應用中使用 AspectJ 注解, 必須在 classpath 下包含 AspectJ 類庫: aopalliance.jar、aspectj.weaver.jar 和 spring-aspects.jar
  • 將aopSchema添加到 beans根元素中
  • 要在 Spring IOC 容器中啟用 AspectJ 注解支持,只要在Bean配置文件中定義一個空的XML元素<aop:aspectj-autoproxy>
  • 當 Spring IOC 容器偵測到 Bean 配置文件中的 <aop:aspectj-autoproxy> 元素時,會自動為與 AspectJ 切面匹配的 Bean 創(chuàng)建代理

2、用 AspectJ 注解聲明切面

  1. 要在Spring中聲明AspectJ切面只需要在IOC容器中將切面聲明為Bean實例。當在 Spring IOC 容器中初始化 AspectJ 切面之后,Spring IOC 容器就會為那些與 AspectJ 切面相匹配的 Bean 創(chuàng)建代理。
  2. 在AspectJ注解中, 切面只是一個帶有 @Aspect 注解的Java類
  3. 通知是標注有某種注解的簡單的Java方法。
  4. AspectJ 支持 5 種類型的通知注解:
    • @Before: 前置通知,在方法執(zhí)行之前執(zhí)行
    • @After: 后置通知,在方法執(zhí)行之后執(zhí)行
    • @AfterRunning:返回通知,在方法返回結(jié)果之后執(zhí)行
    • @AfterThrowing: 異常通知,在方法拋出異常之后
    • @Around: 環(huán)繞通知,圍繞著方法執(zhí)行

前置通知

  • 前置通知:在方法執(zhí)行之前執(zhí)行的通知。
  • 前置通知使用 @Before 注解, 并將切入點表達式的值作為注解值。

后置通知

  • 后置通知是在連接點完成之后執(zhí)行的,即連接點返回結(jié)果或者拋出異常的時候,下面的后置通知記錄了方法的終止。
  • 一個切面可以包括一個或者多個通知。

返回通知

  • 無論連接點是正常返回還是拋出異常,后置通知都會執(zhí)行。如果只想在連接點返回的時候記錄日志, 應使用返回通知代替后置通知。
  • 在返回通知中, 只要將 returning 屬性添加到 @AfterReturning 注解中, 就可以訪問連接點的返回值。 該屬性的值即為用來傳入返回值的參數(shù)名稱。
  • 必須在通知方法的簽名中添加一個同名參數(shù)。在運行時,Spring AOP 會通過這個參數(shù)傳遞返回值。
  • 原始的切點表達式需要出現(xiàn)在pointcut屬性中。

異常通知

  • 只在連接點拋出異常時才執(zhí)行異常通知。
  • 將Throwing屬性添加到 @AfterThrowing 注解中, 也可以訪問連接點拋出的異常. Throwable 是所有錯誤和異常類的超類,所以在異常通知方法可以捕獲到任何錯誤和異常。
  • 如果只對某種特殊的異常類型感興趣, 可以將參數(shù)聲明為其他異常的參數(shù)類型, 然后通知就只在拋出這個類型及其子類的異常時才被執(zhí)行。

環(huán)繞通知

  • 環(huán)繞通知是所有通知類型中功能最為強大的, 能夠全面地控制連接點, 甚至可以控制是否執(zhí)行連接點。
  • 對于環(huán)繞通知來說,連接點的參數(shù)類型必須是ProceedingJoinPoint ,它是 JoinPoint 的子接口,允許控制何時執(zhí)行,是否執(zhí)行連接點。
  • 在環(huán)繞通知中需要明確調(diào)用ProceedingJoinPoint的proceed()方法來執(zhí)行被代理的方法.如果忘記這樣做就會導致通知被執(zhí)行了,但目標方法沒有被執(zhí)行。
  • 注意: 環(huán)繞通知的方法需要返回目標方法執(zhí)行之后的結(jié)果,即調(diào)用 joinPoint.proceed()的返回值,否則會出現(xiàn)空指針異常。

實現(xiàn)代碼

1、Calc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.ycfxhsw.aop"></context:component-scan>
    <!-- 使用AspactJ,注解起作用:自動為匹配的類生成代理對象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

2、Calc接口

public interface Calc {
    // 加法
    int Addition(int i, int j);
    // 減法
    int Subtraction(int i, int j);
    // 乘法
    int Multiplication(int i, int j);
    // 除法
    int Division(int i, int j);
}

3、接口實現(xiàn)CalcImp

import org.springframework.stereotype.Component;
@Component
public class CalcImp implements Calc {
    public int Addition(int i, int j) {
        int result = i + j;
        return result;
    }
    public int Subtraction(int i, int j) {
        int result = i + j;
        return result;
    }
    public int Multiplication(int i, int j) {
        int result = i + j;
        return result;
    }
    public int Division(int i, int j) {
        int result = i + j;
        return result;
    }
}

4、LoggingAspect

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
// @Order(1) 指定切面優(yōu)先級
@Component
@Aspect
public class LoggingAspect {
    /**
     * 申明切入點表達式,一般該方法內(nèi)不需要添加其他方法
     * 使用 @Pointcut 申明切入點表達式
     * 后面的切入點直接使用方法名
     */
    @Pointcut("execution(public int com.ycfxhsw.aop.Calc.*(..))")
    public void DeclareJoinPointExpression() {
    }
    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("execution(public int com.ycfxhsw.aop.Calc.*(int, int))")
    public void BeforeMethod(JoinPoint joinPoint) {
        String MethodName = joinPoint.getSignature().getName();
        List<Object> list = Arrays.asList(joinPoint.getArgs());
        System.out.println("Method Starts..." + MethodName + " with " + list);
    }
    /**
     * 后置通知(無論有無異常)
     * 不能訪問目標方法的執(zhí)行結(jié)果
     * @param joinPoint * com.ycfxhsw.aop.Calc.*(..)
     * 重用 DeclareJoinPointExpression()
     */
    @After("DeclareJoinPointExpression()")
    public void AfterMethod(JoinPoint joinPoint) {
        String MethodName = joinPoint.getSignature().getName();
        System.out.println("Method Ends..." + MethodName);
    }
    /**
     * 返回通知
     * 在方法正常結(jié)束后執(zhí)行
     * 可以訪問目標方法的執(zhí)行結(jié)果
     * @param joinPoint,result
     */
    @AfterReturning(value = "execution(public int com.ycfxhsw.aop.Calc.*(..))", returning = "result")
    public void AfterReturningMethod(JoinPoint joinPoint, Object result) {
        String MethodName = joinPoint.getSignature().getName();
        System.out.println("Method AfterReturning..." + MethodName + " --> " + result);
    }
    /**
     * 異常通知
     * @param joinPoint,exception
     */
    @AfterThrowing(value = "execution(public int com.ycfxhsw.aop.Calc.*(..))", throwing = "exception")
    public void AfterThrowingMethod(JoinPoint joinPoint, Exception exception) {
        String MethodName = joinPoint.getSignature().getName();
        System.out.println("Method AfterThrowing..." + MethodName + " --> " + exception);
    }
    /**
     * 環(huán)繞通知,需要攜帶 ProceedingJoinPoint 類型的參數(shù)
     * 類似于動態(tài)代理全過程
     * 必須有返回值(目標方法返回值)
     * @param proceedingJoinPoint
     @Around("execution(public int com.ycfxhsw.aop.Calc.*(..))")
     public Object AroundMethod(ProceedingJoinPoint proceedingJoinPoint) {
     Object result = null;
     String methodName = proceedingJoinPoint.getSignature().getName();
     try {
     // 前置通知
     System.out.println("The method " + methodName + " begins with " + Arrays.asList(proceedingJoinPoint.getArgs()));
     // 執(zhí)行目標方法
     result = proceedingJoinPoint.proceed();
     // 返回通知
     System.out.println("The method " + methodName + " ends with " + result);
     } catch (Throwable e) {
     // 異常通知
     System.out.println("The method " + methodName + " occurs exception:" + e);
     throw new RuntimeException(e);
     }
     // 后置通知
     System.out.println("The method " + methodName + " ends");
     return result;
     }
     */
}

5、測試Main

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 測試
 */
public class Main {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Calc.xml");
        Calc calc = applicationContext.getBean(Calc.class);
        System.out.println(calc.getClass().getName());
        int resultAdd = calc.Addition(5, 6);
        System.out.println("result-->" + resultAdd + "\n");
        int resultSub = calc.Subtraction(9, 3);
        System.out.println("result-->" + resultSub + "\n");
        int resultMul = calc.Multiplication(8, 6);
        System.out.println("result-->" + resultMul + "\n");
        int resultDiv = calc.Division(99, 3);
        System.out.println("result-->" + resultDiv + "\n");
    }
}

3、指定切面的優(yōu)先級

  • 在同一個連接點上應用不止一個切面時,除非明確指定,否則它們的優(yōu)先級是不確定的.
  • 切面的優(yōu)先級可以通過實現(xiàn) Ordered 接口或利用 @Order 注解指定.
  • 實現(xiàn) Ordered 接口, getOrder() 方法的返回值越小, 優(yōu)先級越高.
  • 若使用 @Order 注解,序號出現(xiàn)在注解中

4、重用切入點定義

  • 在編寫 AspectJ 切面時,可以直接在通知注解中書寫切入點表達式,但同一個切點表達式可能會在多個通知中重復出現(xiàn)。
  • 在 AspectJ 切面中, 可以通過 @Pointcut注解將一個切入點聲明成簡單的方法,切入點的方法體通常是空的,因為將切入點定義與應用程序邏輯混在一起是不合理的。
  • 切入點方法的訪問控制符同時也控制著這個切入點的可見性,如果切入點要在多個切面中共用, 最好將它們集中在一個公共的類中,在這種情況下, 它們必須被聲明為 public。在引入這個切入點時,必須將類名也包括在內(nèi),如果類沒有與這個切面放在同一個包中, 還必須包含包名。
  • 其他通知可以通過方法名稱引入該切入點。

到此這篇關于詳解Spring中的AOP及AspectJ五大通知注解的文章就介紹到這了,更多相關Spring的AOP及AspectJ內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java maven詳細介紹

    Java maven詳細介紹

    今天給大家復習一下Java基礎知識,簡單介紹Maven,文中有非常詳細的解釋,對Java初學者很有幫助喲,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-09-09
  • 在Maven下代理服務器設定的方式

    在Maven下代理服務器設定的方式

    今天小編就為大家分享一篇關于在Maven下代理服務器設定的方式,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • 例舉fastJson和jackson轉(zhuǎn)json的區(qū)別

    例舉fastJson和jackson轉(zhuǎn)json的區(qū)別

    今天小編就為大家分享一篇關于例舉fastJson和jackson轉(zhuǎn)json的區(qū)別,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • java實現(xiàn)驗證碼類生成中文驗證碼

    java實現(xiàn)驗證碼類生成中文驗證碼

    java實現(xiàn)的漢字輸入驗證碼,主要包含兩個類,一個是生成驗證碼,一個是判斷驗證碼輸入是否正確,實現(xiàn)原理非常簡單,將漢字和干擾線生成圖片并將漢字保存到session,前臺獲取每次生成驗證碼圖片并用文本框值和session值比較,功能就怎么簡單
    2014-01-01
  • java顯示當前運行時的參數(shù)(java運行參數(shù))

    java顯示當前運行時的參數(shù)(java運行參數(shù))

    這篇文章主要介紹了java顯示當前運行時參數(shù)的示例(java運行參數(shù)),需要的朋友可以參考下
    2014-04-04
  • 使用maven命令實現(xiàn)下載依賴jar

    使用maven命令實現(xiàn)下載依賴jar

    這篇文章主要介紹了使用maven命令實現(xiàn)下載依賴jar方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 淺析EasyExcel如何導出自動回顯中文

    淺析EasyExcel如何導出自動回顯中文

    這篇文章主要為大家詳細介紹了EasyExcel如何通過全局轉(zhuǎn)換器和自定義注解實現(xiàn)導出自動回顯中文,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-04-04
  • Java數(shù)組的遍歷與求和知識點

    Java數(shù)組的遍歷與求和知識點

    本篇文章給大家總計了Java數(shù)組的遍歷與求和的知識點以及需要注意的地方,需要的朋友參考學習下。
    2018-02-02
  • SpringBoot項目實現(xiàn)jar包方式打包部署

    SpringBoot項目實現(xiàn)jar包方式打包部署

    SpringBoot默認的打包方式就是jar包,本文就來介紹一下SpringBoot項目實現(xiàn)jar包方式打包部署,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • Java 中的 Unsafe 魔法類的作用大全

    Java 中的 Unsafe 魔法類的作用大全

    Unsafe是位于sun.misc包下的一個類,主要提供一些用于執(zhí)行低級別、不安全操作的方法,關于Java 中的 Unsafe 魔法類,到底有啥用處,你都了解嗎,下面通過本文給大家普及一下
    2021-06-06

最新評論

阿坝县| 中西区| 海淀区| 怀来县| 邳州市| 长春市| 攀枝花市| 武宁县| 贵溪市| 和林格尔县| 白玉县| 双辽市| 武鸣县| 武强县| 六安市| 特克斯县| 汝城县| 西乌珠穆沁旗| 渭南市| 大田县| 清徐县| 浦东新区| 金川县| 同德县| 肇源县| 沙坪坝区| 台中县| 贵溪市| 鹿邑县| 丰城市| 绥阳县| 汶川县| 江油市| 石棉县| 尼玛县| 专栏| 洛浦县| 迁西县| 彰化县| 稻城县| 社旗县|