1. 簡(jiǎn)介Spring AOP是Spring框架的一個(gè)重要組成部分,它允許開發(fā)者定義跨多個(gè)模塊的橫切關(guān)注點(diǎn),例如日志記錄、事務(wù)管理、安全等。控制流切入和引" />
環(huán)境:Spring5.3.23
本篇文章將介紹兩個(gè)主題:
Spring AOP是Spring框架的一個(gè)重要組成部分,它允許開發(fā)者定義跨多個(gè)模塊的橫切關(guān)注點(diǎn),例如日志記錄、事務(wù)管理、安全等。控制流切入和引介通知是Spring AOP中的兩個(gè)關(guān)鍵特性,它們能夠增強(qiáng)程序的可維護(hù)性和可讀性。本文將深入探討這兩個(gè)特性的工作原理和使用方法。
控制流切入允許我們根據(jù)方法調(diào)用的控制流來(lái)定義切入點(diǎn)。控制流切入點(diǎn)與當(dāng)前調(diào)用堆棧匹配。例如,如果連接點(diǎn)被com.pack.service包中的方法或PersonService類調(diào)用,它可能會(huì)觸發(fā)。控制流切入點(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)。
@Componentpublic class PersonDAO { public void save(String name) { System.out.println("PersonDAO save method invoke...") ; }}@Componentpublic class PersonService { @Resource private PersonDAO dao ; public void save(String name) { System.out.println("PersonService save method inovke...") ; this.dao.save(name) ; }}
低級(jí)切面Advisor,平時(shí)使用的@Aspect算是高級(jí)切面類,而這些高級(jí)切面類最終會(huì)被轉(zhuǎn)換為Advisor低級(jí)切面類。
@Componentpublic 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)類能知道:
結(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)控制)。
引介通知相對(duì)比較簡(jiǎn)單直接可以在@Aspect切面類中定義
// 這個(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...") ; }}
切面類
@Aspectpublic 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è)重要概念。控制流切入點(diǎn)用于在特定的控制流條件下切入代碼,而引介通知?jiǎng)t讓目標(biāo)類具有更加強(qiáng)大的能力。
本文鏈接:http://www.www897cc.com/showinfo-26-55297-0.html漲知識(shí)!Spring AOP還能這么玩,看看你的項(xiàng)目能否用上
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: 代碼分析利器,你值得擁有