自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

漲知識(shí)!Spring AOP還能這么玩,看看你的項(xiàng)目能否用上

開發(fā) 前端
UserService能正確的轉(zhuǎn)換為CommonManager類,這說(shuō)明UserService生成的代理類實(shí)現(xiàn)了CommonManager接口類,同時(shí)在執(zhí)行方法調(diào)用的時(shí)候使用的是我們制定的默認(rèn)實(shí)現(xiàn)類DefaultCommonManager。?

環(huán)境:Spring5.3.23

本篇文章將介紹兩個(gè)主題:

  • 控制流切入點(diǎn)(動(dòng)態(tài)切入點(diǎn))
  • 引介通知

1. 簡(jiǎn)介

Spring AOP是Spring框架的一個(gè)重要組成部分,它允許開發(fā)者定義跨多個(gè)模塊的橫切關(guān)注點(diǎn),例如日志記錄、事務(wù)管理、安全等??刂屏髑腥牒鸵橥ㄖ荢pring AOP中的兩個(gè)關(guān)鍵特性,它們能夠增強(qiáng)程序的可維護(hù)性和可讀性。本文將深入探討這兩個(gè)特性的工作原理和使用方法。

控制流切入

控制流切入允許我們根據(jù)方法調(diào)用的控制流來(lái)定義切入點(diǎn)??刂屏髑腥朦c(diǎn)與當(dāng)前調(diào)用堆棧匹配。例如,如果連接點(diǎn)被com.pack.service包中的方法或PersonService類調(diào)用,它可能會(huì)觸發(fā)??刂屏髑腥朦c(diǎn)是通過(guò)使用org.springframework.aop.support.ControlFlowPointcut類指定的。

引介通知

引介通知能夠聲明被建議的對(duì)象實(shí)現(xiàn)給定的接口,并代表這些對(duì)象提供該接口的實(shí)現(xiàn)。簡(jiǎn)單說(shuō):你有個(gè)PersonService類,引介通知能夠讓你不修改代碼的情況下去實(shí)現(xiàn)你給定的任意接口(CommonDAO)。

2. 實(shí)戰(zhàn)案例

2.1 控制流切入點(diǎn)

準(zhǔn)備基礎(chǔ)類

@Component
public class PersonDAO {
  public void save(String name) {
    System.out.println("PersonDAO save method invoke...") ;
  }
}
@Component
public class PersonService {
  @Resource
  private PersonDAO dao ;
  public void save(String name) {
    System.out.println("PersonService save method inovke...") ;
    this.dao.save(name) ;
  }
}

定義切面類Advisor

低級(jí)切面Advisor,平時(shí)使用的@Aspect算是高級(jí)切面類,而這些高級(jí)切面類最終會(huì)被轉(zhuǎn)換為Advisor低級(jí)切面類。

@Component
public class PackControlFlowAdvisor extends DefaultPointcutAdvisor {
  private static MethodInterceptor logInterceptor = invocation -> {
    System.out.println("before log...") ;
    Object ret = invocation.proceed() ;
    System.out.println("after log...") ;
    return ret ;
  } ;
  // 要進(jìn)行匹配的類
  private static Class<?> clazz = PersonService.class ;
  // 要進(jìn)行匹配的方法(可以為null,這樣指定類中的所有方法都會(huì)被匹配攔截)
  private static String methodName = "save" ;
  private static ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName) ;
  public PackControlFlowAdvisor() {
    super(pointcut, logInterceptor) ;
  }
}

測(cè)試

PersonService ps = context.getBean(PersonService.class) ;
ps.save("王五") ;

控制臺(tái)輸出

PersonService save method inovke...
before log...
PersonDAO save method invoke...
after log...

PersonDAO中的save方法被攔截了。什么意思?怎么PersonDAO就被攔截了,先來(lái)看上面切點(diǎn)的定義ControlFlowPointcut

public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher {
  public boolean matches(Class<?> clazz) {
    return true;
  }
  public boolean matches(Method method, Class<?> targetClass) {
    return true;
  }
  public boolean isRuntime() {
    return true;
  }
  public boolean matches(Method method, Class<?> targetClass, Object... args) {
    // 取得當(dāng)前線程的整個(gè)執(zhí)行棧(方法的調(diào)用)
    for (StackTraceElement element : new Throwable().getStackTrace()) {
      if (element.getClassName().equals(this.clazz.getName()) &&
          (this.methodName == null || element.getMethodName().equals(this.methodName))) {
        return true;
      }
    }
    return false;
  }
}

通過(guò)在這個(gè)切點(diǎn)類能知道:

  1. 當(dāng)前容器中的所有類都會(huì)被代理;因?yàn)檫@里的類匹配直接返回true,2個(gè)參數(shù)的matches直接返回true,最后isRuntime返回true,最終執(zhí)行3個(gè)參數(shù)的matches方法。
  2. 每個(gè)類中方法的調(diào)用都會(huì)獲取當(dāng)前執(zhí)行的棧,都會(huì)進(jìn)行判斷類及方法是否被匹配。

結(jié)合上面的測(cè)試輸出結(jié)果,PersonDAO#save方法被攔截了,因?yàn)樗掀ヅ錀l件,在PersonService#save方法中調(diào)用了PersonDAO#save方法,那PersonDAO#save方法執(zhí)行棧中就包含了PersonService#save正好匹配了我們定義的切點(diǎn)。

簡(jiǎn)單說(shuō):某個(gè)類中的某個(gè)方法調(diào)用時(shí)會(huì)判斷當(dāng)前整個(gè)執(zhí)行棧中是否有設(shè)定好的類及方法,如果有則攔截當(dāng)前的方法(執(zhí)行通知)。

注意:控制流切入點(diǎn)比正常切入點(diǎn)慢10-15倍,但在某些情況下它們是有用的。所以大家還是慎重使用吧,畢竟所有的類都被代理了(當(dāng)然這里我們可以自定義matches來(lái)控制)。

2.2 引介通知

引介通知相對(duì)比較簡(jiǎn)單直接可以在@Aspect切面類中定義

注備基礎(chǔ)類

// 這個(gè)接口是我們準(zhǔn)備讓其它類實(shí)現(xiàn)的
public interface CommonManager {
  void calc(int a, int b) ;
}
// 默認(rèn)實(shí)現(xiàn)
public class DefaultCommonManager implements CommonManager {
  @Override
  public void calc(int a, int b) {
    System.out.printf("計(jì)算a + b = %d%n", (a + b)) ;
  }
}
// 該類是我們將要通過(guò)引介增強(qiáng)讓其實(shí)現(xiàn)CommonManager類
@Component("us")
public class UserService {
  public void save() {
    System.out.println("UserService save...") ;
  }
}

切面類

@Aspect
public static class CommonAspect {
  /**
   * 這樣聲明后,匹配的類就會(huì)自動(dòng)的實(shí)現(xiàn)這里指定的CommonManager接口,默認(rèn)的實(shí)現(xiàn)類是使用DefaultCommonManager
   * value:該值決定了哪些類會(huì)被增強(qiáng)(實(shí)現(xiàn)指定的CommonManager接口)
   */
  @DeclareParents(value = "com.pack.main.aop_introductionadviser.IntructionDeclareMain2.*+", defaultImpl = DefaultCommonManager.class)
  public static CommonManager mixin;
}

注意:在這個(gè)切面類中我們并沒(méi)有定義@Before,@Around等同志。

測(cè)試

CommonManager c = (CommonManager) context.getBean("us") ;
c.calc(10, 20) ;

控制臺(tái)輸出

計(jì)算a + b = 30

UserService能正確的轉(zhuǎn)換為CommonManager類,這說(shuō)明UserService生成的代理類實(shí)現(xiàn)了CommonManager接口類,同時(shí)在執(zhí)行方法調(diào)用的時(shí)候使用的是我們制定的默認(rèn)實(shí)現(xiàn)類DefaultCommonManager。

總結(jié):控制流切入點(diǎn)(ControlFlowPointcut)和引介通知(@DeclareParents)是Spring AOP的兩個(gè)重要概念??刂屏髑腥朦c(diǎn)用于在特定的控制流條件下切入代碼,而引介通知?jiǎng)t讓目標(biāo)類具有更加強(qiáng)大的能力。

責(zé)任編輯:武曉燕 來(lái)源: Spring全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2022-10-31 08:47:21

人臉識(shí)別按鍵鍵盤

2024-07-10 11:26:18

2024-05-17 09:37:26

format屬性Spring

2020-05-09 16:45:56

ping命令Linux

2024-03-25 08:03:32

技術(shù)面試ShowMeBug協(xié)同編程

2024-10-28 07:10:00

scroll標(biāo)記前端網(wǎng)格布局

2021-03-02 10:50:23

SpringMVC 參數(shù)JavaWeb

2022-08-12 08:25:33

Python異常信息代碼

2020-08-14 08:19:25

Shell命令行數(shù)據(jù)

2017-03-07 09:49:18

存儲(chǔ)

2021-04-01 05:40:53

分庫(kù)分表數(shù)據(jù)庫(kù)MySQL

2022-01-04 08:00:48

前端技術(shù)Esbuild

2021-02-16 16:43:21

工具性能調(diào)優(yōu)

2019-01-29 10:00:59

GitHub開源搜索

2016-12-02 20:43:28

Android

2017-12-06 15:14:51

AndroidItemRecyclerVie

2020-01-07 10:35:21

QQQQ群手機(jī)QQ

2024-01-18 15:43:37

Linuxaxel工具

2021-01-04 14:16:01

小程序地圖騰訊

2020-10-12 06:28:05

動(dòng)態(tài)IP框架
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)