因爲 Cglib 自己的設計,沒法實如今 Proxy 外面再包裝一層 Proxy(JDK Proxy 能夠),一般會報以下錯誤:java
Caused by: java.lang.ClassFormatError: Duplicate method name "newInstance" with signature ".......... at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ... 10 more
錯誤來源代碼:spring
net.sf.cglib.proxy.Enhancer#generateClass(ClassVisitor v)ide
......省略代碼 // 如下部分的字節碼,每次生成 Proxy 實例都會插入。JVM 驗證字節碼時則會報錯。 if (useFactory || currentData != null) { int[] keys = getCallbackKeys(); emitNewInstanceCallbacks(e); emitNewInstanceCallback(e); emitNewInstanceMultiarg(e, constructorInfo); emitGetCallback(e, keys); emitSetCallback(e, keys); emitGetCallbacks(e); emitSetCallbacks(e); }
經過 dump 出來的字節碼查看則更爲直觀:this
生成的字節碼中,newInstance 方法是重複的。設計
dump 方法: System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");
3d
實現多重代理,有一種蹩腳的方法,例如 JDK 和 Cglib 組合使用。或者你直接使用 JDK 代理。但有時候,針對類的操做還行不通。代理
筆者參考 Spring 的作法,實現了一個簡單的多重代理。code
Spring 的場景是:一個目標方法被多個 AOP 攔截,此時就須要多重代理。orm
Spring 建立代理的代碼位於 :org.springframework.aop.framework.CglibAopProxy#getProxy對象
Spring AOP 攔截器類:org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor
該類的 intercept 方法是實現多重代理的核心。
每次調用目標方法,都會根據目標方法,和目標方法的多個攔截點生成一個調用對象。
// 生成調用對象 CglibMethodInvocation c = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy); // 調用 c.proceed();
而後調用父類 proceed 方法,其實就是一個過濾器模式:
public Object proceed() throws Throwable { if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // Skip this interceptor and invoke the next in the chain. 遞歸. return proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
注意最後一行,這裏就是調用攔截點的 invoke 方法,這個攔截點的具體實現類:AspectJAroundAdvice。
看下他的 invoke 方法:
public Object invoke(MethodInvocation mi) throws Throwable { ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; // AOP 裏熟悉的 ProceedingJoinPoint 參數!!!! ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); return invokeAdviceMethod(pjp, jpm, null, null); }
一般,咱們在業務中編寫 AOP 攔截代碼時,都會接觸到這個 ProceedingJoinPoint 參數,而後調用他的 proceed 方法調用目標方法。
這個 ProceedingJoinPoint 類的 proceed 方法最終會回調 DynamicAdvisedInterceptor 對的 proceed 方法。直到全部的攔截點所有執行完畢。最終執行目標類的方法。
因此,你設置的每一個被攔截的方法,若是這個方法會被攔截屢次,那麼就會有多個 MethodInterceptor(不是 cglib 的)實例造成調用鏈。而後經過 ProceedingJoinPoint 傳遞給你攔截使用。
鋪墊了這麼多,咱們本身來實現一個簡單的,不能像 Spring 這麼複雜!!!!
先說一下思路:事實上很簡單,只須要再攔截器裏放一個過濾器鏈便可,用戶在過濾器裏攔截多重調用。這些攔截器,就像你加 @Around 註解的方法,只不過咱們這裏沒有 Spring 那麼方便而已。
畫個 UML 圖:
代碼以下:
Test.java & SayHello.java
public class Test { public static void main(String[] args) { Object proxy = ProxyFactory.create().getProxy(new SayHello()); proxy.toString(); } static class SayHello { @Override public String toString() { return "hello cglib !"; } } }
ProxyFactory.java & Interceptor.java
public class ProxyFactory { private ProxyFactory() {} public static ProxyFactory create() { return new ProxyFactory(); } public Object getProxy(Object origin) { final Enhancer en = new Enhancer(); en.setSuperclass(origin.getClass()); List<Chain.Point> list = new ArrayList<>(); list.add(new Point1()); list.add(new Point2()); en.setCallback(new Interceptor(new Chain(list, origin))); return en.create(); } private class Interceptor implements MethodInterceptor { Chain chain; public Interceptor(Chain chain) { this.chain = chain; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return chain.proceed(); } } }
Chain.java & Point.java
public class Chain { private List<Point> list; private int index = -1; private Object target; public Chain(List<Point> list, Object target) { this.list = list; this.target = target; } public Object proceed() { Object result; if (++index == list.size()) { result = (target.toString()); System.err.println("Target Method invoke result : " + result); } else { Point point = list.get(index); result = point.proceed(this); } return result; } interface Point { Object proceed(Chain chain); } }
Point1.java & Point2.java
public class Point1 implements Chain.Point { @Override public Object proceed(Chain chain) { System.out.println("point 1 before"); Sleep.sleep(20); Object result = chain.proceed(); Sleep.sleep(20); System.out.println("point 1 after"); return result; } } public class Point2 implements Chain.Point { @Override public Object proceed(Chain chain) { System.out.println("point 2 before"); Sleep.sleep(20); Object result = chain.proceed(); Sleep.sleep(20); System.out.println("point 2 after"); return result; } }
運行 Test main 結果:
符合預期。