欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

AOP 基本概念

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

AOP 的主要編程對(duì)象是切面(aspect), 切面模塊化橫切關(guān)注點(diǎn)

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

AOP 的好處:

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

AOP術(shù)語

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

AspectJ

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

應(yīng)用

本文以一個(gè)簡(jiǎn)單計(jì)算器為代碼例子

AOP

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

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

2、用 AspectJ 注解聲明切面

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

前置通知

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

后置通知

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

返回通知

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

異常通知

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

環(huán)繞通知

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

實(shí)現(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,注解起作用:自動(dòng)為匹配的類生成代理對(duì)象 -->
    <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、接口實(shí)現(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)先級(jí)
@Component
@Aspect
public class LoggingAspect {
    /**
     * 申明切入點(diǎn)表達(dá)式,一般該方法內(nèi)不需要添加其他方法
     * 使用 @Pointcut 申明切入點(diǎn)表達(dá)式
     * 后面的切入點(diǎn)直接使用方法名
     */
    @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);
    }
    /**
     * 后置通知(無論有無異常)
     * 不能訪問目標(biāo)方法的執(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í)行
     * 可以訪問目標(biāo)方法的執(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ù)
     * 類似于動(dòng)態(tài)代理全過程
     * 必須有返回值(目標(biāo)方法返回值)
     * @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í)行目標(biāo)方法
     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、測(cè)試Main

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 測(cè)試
 */
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)先級(jí)

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

4、重用切入點(diǎn)定義

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

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

相關(guān)文章

  • 你應(yīng)該知道的21個(gè)Java核心技術(shù)

    你應(yīng)該知道的21個(gè)Java核心技術(shù)

    Java的21個(gè)核心技術(shù)點(diǎn),你知道嗎?這篇文章主要為大家詳細(xì)介紹了Java核心技術(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Java全面分析面向?qū)ο笾^承

    Java全面分析面向?qū)ο笾^承

    繼承就是可以直接使用前輩的屬性和方法。自然界如果沒有繼承,那一切都是處于混沌狀態(tài)。多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作
    2022-04-04
  • 手把手帶你實(shí)現(xiàn)一個(gè)萌芽版的Spring容器

    手把手帶你實(shí)現(xiàn)一個(gè)萌芽版的Spring容器

    大家好,我是老三,Spring是我們最常用的開源框架,經(jīng)過多年發(fā)展,Spring已經(jīng)發(fā)展成枝繁葉茂的大樹,讓我們難以窺其全貌,這節(jié),我們回歸Spring的本質(zhì),五分鐘手?jǐn)]一個(gè)Spring容器,揭開Spring神秘的面紗
    2022-03-03
  • Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能實(shí)例

    分頁功能是我們?nèi)粘i_發(fā)中經(jīng)常會(huì)遇到的,下面這篇文章主要給大家介紹了Spring MVC+MyBatis+MySQL實(shí)現(xiàn)分頁功能的相關(guān)資料,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-06-06
  • Java調(diào)用IK分詞器進(jìn)行分詞方式,封裝工具類

    Java調(diào)用IK分詞器進(jìn)行分詞方式,封裝工具類

    這篇文章主要介紹了Java調(diào)用IK分詞器進(jìn)行分詞方式,封裝工具類,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • springboot如何開啟一個(gè)監(jiān)聽線程執(zhí)行任務(wù)

    springboot如何開啟一個(gè)監(jiān)聽線程執(zhí)行任務(wù)

    這篇文章主要介紹了springboot如何開啟一個(gè)監(jiān)聽線程執(zhí)行任務(wù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • mybatis的dtd約束文件及配置文件xml自動(dòng)提示操作

    mybatis的dtd約束文件及配置文件xml自動(dòng)提示操作

    這篇文章主要介紹了mybatis的dtd約束文件及配置文件xml自動(dòng)提示操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java中可以通過Thread類和Runnable接口來創(chuàng)建多個(gè)線程,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • JAVA字符串類型switch的底層原理詳析

    JAVA字符串類型switch的底層原理詳析

    這篇文章主要給大家介紹了關(guān)于JAVA字符串類型switch的底層原理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用JAVA具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Linux系統(tǒng)Java環(huán)境配置教程

    Linux系統(tǒng)Java環(huán)境配置教程

    這篇文章給大家介紹的Linux 系統(tǒng)Java環(huán)境配置教程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2018-05-05

最新評(píng)論