javascript
[Done]Spring @Pointcut 切点调用不到(SpringAOP嵌套方法不起作用) 注意事项
今天在開發(fā)過程中,遇到一個問題卡了很久,測試代碼如下:
package spring.pointcut;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut;/*** @Description: Pointcut測試* @Author: qionghui.fang* @Date: 2018/10/23 上午10:10*/ @Aspect public class TargetMonitor {// 配置方法1 // @Pointcut("execution(* spring.pointcut.Target.onEvent(String))") // private void anyMethod() {} // @Around("anyMethod()")//配置方法2@Around("execution(* spring.pointcut.Target.onEvent(..))")public Object monitor(ProceedingJoinPoint point) throws Throwable {System.out.println("before");try {return point.proceed();} finally {System.out.println("after");}} }目標(biāo)類:
public class Target {public void otherEvent(){System.out.println("Call otherEvent()");}public boolean onEvent(Integer type, Long Value){System.out.println("Call onEvent(Integer type, Long Value)");for (int i=0; i<=3; i++){onEvent("");}System.out.println("End Call onEvent(Integer type, Long Value)");return true;}public boolean onEvent(String type){System.out.println("Call onEvent(String type)");return true;}}Main方法:
public class Main {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("spring/spring.xml");Target target = (Target) ctx.getBean("target");System.out.println("\n*****************************");target.onEvent(1,1L);System.out.println("\n*****************************");target.onEvent("");System.out.println("\n*****************************");target.otherEvent();System.out.println("\n*****************************");} }spring.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><bean id="target" class="spring.pointcut.Target"/><bean id="monitor" class="spring.pointcut.TargetMonitor"/><!-- 基于@AspectJ切面的驅(qū)動器 --><aop:aspectj-autoproxy proxy-target-class="true"/></beans>結(jié)果輸出:
22:14:25.092 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'target'***************************** 22:14:25.096 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'monitor' before Call onEvent(Integer type, Long Value) Call onEvent(String type) Call onEvent(String type) Call onEvent(String type) Call onEvent(String type) End Call onEvent(Integer type, Long Value) after***************************** before Call onEvent(String type) after***************************** Call otherEvent()*****************************問題描述:
在目標(biāo)類里有兩個同名的onEvent方法,下面這個是目標(biāo)切點方法,但是系統(tǒng)調(diào)用時,方法入口是上面的onEvent方法,所以怎么都執(zhí)行不到想要的邏輯。
其實想一想動態(tài)代理,是代理的類這一層級,關(guān)于類中方法的相互調(diào)用,是不能侵入這么深的。
注意:切點方法當(dāng)前僅當(dāng)在類執(zhí)行入口時才能被調(diào)用,而非類內(nèi)部的其他接口調(diào)用。
?
原理跟蹤,跟蹤生成的動態(tài)代理類:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import spring.dynamicproxy.IFace;public final class Target1$Proxy extends Proxy implements Target {private static Method m1;private static Method m2;private static Method m3;private static Method m4;private static Method m5;private static Method m0;static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m3 = Class.forName("spring.dynamicproxy.Target").getMethod("onEvent");m4 = Class.forName("spring.dynamicproxy.Target").getMethod("onEvent1");m5 = Class.forName("spring.dynamicproxy.Target").getMethod("otherEvent");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}public Target1$Proxy(InvocationHandler var1) throws {super(var1);}public final boolean onEvent() throws {try {return (Boolean)super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final boolean onEvent1() throws {try {return (Boolean)super.h.invoke(this, m4, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void otherEvent() throws {try {super.h.invoke(this, m5, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}}?
上述省略了部分其他方法,大家關(guān)注這個動態(tài)代理類內(nèi)容,
JDK的動態(tài)代理核心是生成了一個新的代理類,這個代理類基礎(chǔ)Proxy類,實現(xiàn)了目標(biāo)對象的接口,而在具體方法執(zhí)行時,
調(diào)用super.h.invoke,這里的super.h 是指我們初始化動態(tài)代理的InvocationHandler,這里有點繞,大家要好好理解。
也就是說動態(tài)代理生效的方法是,當(dāng)調(diào)用代理類Target.m的目標(biāo)方法時,其實執(zhí)行的是ProxyTarget.m,
這樣我們在切點中round前后的邏輯就可以執(zhí)行到。
但是當(dāng)執(zhí)行round中的super.h.invoke時,這個方法里執(zhí)行的是原始類的原生邏輯,比如執(zhí)行上述例子的onEvent1,
但onEnvent1中調(diào)用onEvent時,是執(zhí)行的this.onEvent,而非ProxyTarget.onEvent,
這便是為什么上述例子無法執(zhí)行的底層核心原因。
?
這篇文章也描述了類似的問題:https://blog.csdn.net/bobozai86/article/details/78896487
?
解決辦法:
1、在調(diào)用點使用代理類,而非this調(diào)用:
main中獲取容器對象的測試方法:
?
?
2、思考業(yè)務(wù)層面,是否可以切在更內(nèi)層的方法。
?
本質(zhì)還是要理解動態(tài)代理的實現(xiàn)原理。
?
以上。
?
轉(zhuǎn)載于:https://www.cnblogs.com/do-your-best/p/9839846.html
總結(jié)
以上是生活随笔為你收集整理的[Done]Spring @Pointcut 切点调用不到(SpringAOP嵌套方法不起作用) 注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Gralde 网络代理
- 下一篇: 前端 html border-righ