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

Spring?AOP中三種增強方式的示例詳解

 更新時間:2022年07月04日 10:22:57   作者:wl_Honest  
AOP?(Aspect?Orient?Programming),直譯過來就是?面向切面編程。AOP?是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補充。本文為大家介紹了Spring?AOP中三種增強方式,感興趣的可以了解一下

什么是AOP

AOP (Aspect Orient Programming),直譯過來就是 面向切面編程。AOP 是一種編程思想,是面向?qū)ο缶幊蹋∣OP)的一種補充。面向?qū)ο缶幊虒⒊绦虺橄蟪筛鱾€層次的對象,而面向切面編程是將程序抽象成各個切面。從《Spring實戰(zhàn)(第4版)》圖書中扒了一張圖:

從該圖可以很形象地看出,所謂切面,相當(dāng)于應(yīng)用對象間的橫切點,我們可以將其單獨抽象為單獨的模塊。

為什么需要AOP

想象下面的場景,開發(fā)中在多個模塊間有某段重復(fù)的代碼,我們通常是怎么處理的?顯然,沒有人會靠“復(fù)制粘貼”吧。在傳統(tǒng)的面向過程編程中,我們也會將這段代碼,抽象成一個方法,然后在需要的地方分別調(diào)用這個方法,這樣當(dāng)這段代碼需要修改時,我們只需要改變這個方法就可以了。然而需求總是變化的,有一天,新增了一個需求,需要再多出做修改,我們需要再抽象出一個方法,然后再在需要的地方分別調(diào)用這個方法,又或者我們不需要這個方法了,我們還是得刪除掉每一處調(diào)用該方法的地方。實際上涉及到多個地方具有相同的修改的問題我們都可以通過 AOP 來解決。

AOP術(shù)語

AOP 領(lǐng)域中的特性術(shù)語:

  1. 通知(Advice): AOP 框架中的增強處理。通知描述了切面何時執(zhí)行以及如何執(zhí)行增強處理。
  2. 連接點(join point): 連接點表示應(yīng)用執(zhí)行過程中能夠插入切面的一個點,這個點可以是方法的調(diào)用、異常的拋出。在 Spring AOP 中,連接點總是方法的調(diào)用。
  3. 切點(PointCut): 可以插入增強處理的連接點。
  4. 切面(Aspect): 切面是通知和切點的結(jié)合。
  5. 引入(Introduction):引入允許我們向現(xiàn)有的類添加新的方法或者屬性。
  6. 織入(Weaving): 將增強處理添加到目標(biāo)對象中,并創(chuàng)建一個被增強的對象,這個過程就是織入。

通過注解聲明5種通知類型

Spring AOP 中有 5 中通知類型,分別如下:

本章中主要以@Before、@After和@Around為例展示AOP的增強方式。

首先引入依賴,這里只放aop的依賴,其它的依賴請根據(jù)自己的實際情況引入:

<!-- aop -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.18.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.1.18.RELEASE</version>
</dependency>

接著新建一個切面類TesstAspect,并且定義3個切點,就是后面要測試的3個切點:

package com.wl.standard.aop.aspect;
 
import com.wl.standard.util.JoinPointUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
 
/**
 * @author wl
 * @date 2022/7/2 16:08
 */
@Slf4j
@Component
@Aspect
public class TestAspect {
 
    @Pointcut("execution(public * com.wl.standard.service.TravelRecordService.getAllRecord(..))")
    public void pointCut1(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityRailService.getTopRail(..))")
    public void pointCut2(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityGdpService.compareGDP(..))")
    public void pointCut3(){};
 
}

備注:execution():用于匹配方法執(zhí)行的連接點,第一個*表示匹配任意的方法返回值

@Before

先測試第一個增強方法,在切點方法之前執(zhí)行,因為是簡單測試,就只打印一下日志就好了:

package com.wl.standard.aop.aspect;
 
import com.wl.standard.util.JoinPointUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
 
/**
 * @author wl
 * @date 2022/7/2 16:08
 */
@Slf4j
@Component
@Aspect
public class TestAspect {
 
    @Pointcut("execution(public * com.wl.standard.service.TravelRecordService.getAllRecord(..))")
    public void pointCut1(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityRailService.getTopRail(..))")
    public void pointCut2(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityGdpService.compareGDP(..))")
    public void pointCut3(){};
 
    @Before("pointCut1()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("當(dāng)前線程: {} 開始執(zhí)行查詢前任務(wù)...", Thread.currentThread().getName());
    }
}

啟動項目,進入swagger的頁面調(diào)用接口測試:

調(diào)用接口后,在控制臺可以看到日志打印的先后順序,先執(zhí)行的@Before里的增強方法再執(zhí)行的service里的方法:

@After

接著測試@After,為了更好的展示增強方式,這次利用JoinPoint獲取參數(shù)。

說明:Joinpoint是AOP的連接點。一個連接點代表一個被代理的方法。

為了獲取參數(shù)的方法能夠復(fù)用,這里新建一個工具類JoinPointUtils:

package com.wl.standard.util;
 
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
 
/**
 * JoinPoint 工具類
 * @author wl
 * @date 2022/7/2 21:55
 */
public class JoinPointUtils {
 
    public static <T> T getParamByName(JoinPoint joinPoint, String paramName, Class<T> clazz) {
        // 獲取所有參數(shù)的值
        Object[] args = joinPoint.getArgs();
        // 獲取方法簽名
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // 在方法簽名中獲取所有參數(shù)的名稱
        String[] parameterNames = methodSignature.getParameterNames();
        // 根據(jù)參數(shù)名稱拿到下標(biāo), 參數(shù)值的數(shù)組和參數(shù)名稱的數(shù)組下標(biāo)是一一對應(yīng)的
        int index = ArrayUtils.indexOf(parameterNames, paramName);
        // 在參數(shù)數(shù)組中取出下標(biāo)對應(yīng)參數(shù)值
        Object obj = args[index];
        if (obj == null) {
            return null;
        }
        // 將object對象轉(zhuǎn)為Class返回
        if (clazz.isInstance(obj)) {
            return clazz.cast(obj);
        }
        return (T) obj;
    }
}

接著編寫@After的增強方法,在切點方法之后執(zhí)行:

package com.wl.standard.aop.aspect;
 
import com.wl.standard.util.JoinPointUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
 
/**
 * @author wl
 * @date 2022/7/2 16:08
 */
@Slf4j
@Component
@Aspect
public class TestAspect {
 
    @Pointcut("execution(public * com.wl.standard.service.TravelRecordService.getAllRecord(..))")
    public void pointCut1(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityRailService.getTopRail(..))")
    public void pointCut2(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityGdpService.compareGDP(..))")
    public void pointCut3(){};
 
    @Before("pointCut1()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("當(dāng)前線程: {} 開始執(zhí)行查詢前任務(wù)...", Thread.currentThread().getName());
    }
 
    @After("pointCut2()")
    public void doAfter(JoinPoint joinPoint) {
        Integer index = JoinPointUtils.getParamByName(joinPoint, "index", Integer.class);
        log.info("當(dāng)前線程: {}執(zhí)行完任務(wù),請求參數(shù)值: {}", Thread.currentThread().getName(), index);
    }
}

為了方便理解這里獲取的參數(shù),下面放一下這里切入的方法:

然后一樣的流程,啟動項目,在swagger頁面里調(diào)用接口:

@Around 

前面2個例子一個是在切點之前執(zhí)行,一個是在切點之后執(zhí)行,如果項目中我們想要記錄一個sql執(zhí)行的耗時時間,應(yīng)該怎么做?

@Around環(huán)繞通知:它集成了@Before、@AfterReturing、@AfterThrowing、@After四大通知。需要注意的是,它和其他四大通知注解最大的不同是需要手動進行接口內(nèi)方法的反射后才能執(zhí)行接口中的方法,換言之,@Around其實就是一個動態(tài)代理。

利用@Around的話,就可以編寫一個方法,切入多個切點記錄耗時了:

package com.wl.standard.aop.aspect;
 
import com.wl.standard.util.JoinPointUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
 
/**
 * @author wl
 * @date 2022/7/2 16:08
 */
@Slf4j
@Component
@Aspect
public class TestAspect {
 
    @Pointcut("execution(public * com.wl.standard.service.TravelRecordService.getAllRecord(..))")
    public void pointCut1(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityRailService.getTopRail(..))")
    public void pointCut2(){};
 
    @Pointcut("execution(public * com.wl.standard.service.CityGdpService.compareGDP(..))")
    public void pointCut3(){};
 
    @Before("pointCut1()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("當(dāng)前線程: {} 開始執(zhí)行查詢前任務(wù)...", Thread.currentThread().getName());
    }
 
    @After("pointCut2()")
    public void doAfter(JoinPoint joinPoint) {
        Integer index = JoinPointUtils.getParamByName(joinPoint, "index", Integer.class);
        log.info("當(dāng)前線程: {}執(zhí)行完任務(wù),請求參數(shù)值: {}", Thread.currentThread().getName(), index);
    }
 
    @Around("pointCut3()")
    public Object  doAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        // 調(diào)用執(zhí)行目標(biāo)方法(result為目標(biāo)方法執(zhí)行結(jié)果),必須有此行代碼才會執(zhí)行目標(biāo)調(diào)用的方法(等價于@befor+@after),否則只會執(zhí)行一次之前的(等價于@before)
        Object result = pjp.proceed();
        long end = System.currentTimeMillis();
        log.info(pjp.getTarget().getClass().getSimpleName() + "->" + pjp.getSignature().getName() + " 耗費時間:" + (end - start) + "毫秒");
        return result;
    }
}

啟動項目,調(diào)用接口,看控制臺輸出:

以上就是Spring AOP中三種增強方式的示例詳解的詳細內(nèi)容,更多關(guān)于Spring AOP增強方式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java基礎(chǔ)的詳細了解第三天

    java基礎(chǔ)的詳細了解第三天

    這篇文章對Java編程語言的基礎(chǔ)知識作了一個較為全面的匯總,在這里給大家分享一下。需要的朋友可以參考,希望能給你帶來幫助
    2021-08-08
  • 深入解析Java的線程同步以及線程間通信

    深入解析Java的線程同步以及線程間通信

    這篇文章主要介紹了Java的線程同步以及線程間通信,多線程編程是Java學(xué)習(xí)中的重點和難點,需要的朋友可以參考下
    2015-09-09
  • 詳解spring-boot集成elasticsearch及其簡單應(yīng)用

    詳解spring-boot集成elasticsearch及其簡單應(yīng)用

    本篇文章主要介紹了詳解spring-boot集成elasticsearch及其簡單應(yīng)用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • MybatisPlusInterceptor實現(xiàn)sql攔截器超詳細教程

    MybatisPlusInterceptor實現(xiàn)sql攔截器超詳細教程

    這篇文章主要給大家介紹了關(guān)于MybatisPlusInterceptor實現(xiàn)sql攔截器超詳細教程的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-08-08
  • Java OpenCV4.0.0實現(xiàn)實時人臉識別

    Java OpenCV4.0.0實現(xiàn)實時人臉識別

    這篇文章主要為大家詳細介紹了Java OpenCV4.0.0實現(xiàn)實時人臉識別,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • eclipse安裝spring ide的步驟詳解

    eclipse安裝spring ide的步驟詳解

    這篇文章主要介紹了eclipse安裝spring ide的步驟詳解,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • Jmeter中正則表達式提取器使用詳解

    Jmeter中正則表達式提取器使用詳解

    本文主要介紹了Jmeter中正則表達式提取器使用詳解,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • JAVA DOM解析XML文件過程詳解

    JAVA DOM解析XML文件過程詳解

    這篇文章主要介紹了JAVA DOM解析XML文件過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • SpringBoot?實現(xiàn)全局異常處理的示例代碼

    SpringBoot?實現(xiàn)全局異常處理的示例代碼

    本文主要介紹了SpringBoot實現(xiàn)全局異常處理,全局異常處理器的使用可以顯著提高Spring Boot項目的代碼質(zhì)量和可維護性,減少冗余代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • Java獲取請求頭、參數(shù)、路徑方式

    Java獲取請求頭、參數(shù)、路徑方式

    這篇文章主要介紹了Java獲取請求頭、參數(shù)、路徑方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評論

屏东市| 磐石市| 漳平市| 银川市| 元氏县| 来安县| 衡阳县| 德昌县| 陇西县| 阳城县| 本溪| 万州区| 谢通门县| 左云县| 永德县| 蒲城县| 万源市| 澎湖县| 浏阳市| 呼和浩特市| 新郑市| 原平市| 宜昌市| 温泉县| 龙泉市| 玉山县| 特克斯县| 辰溪县| 武强县| 万源市| 股票| 南阳市| 林芝县| 乌兰察布市| 徐汇区| 泽库县| 博爱县| 翁源县| 临高县| 双峰县| 英山县|