前言
由于 Cglib 本身的设计,无法实现在 Proxy 外面再包装一层 Proxy(JDK Proxy 可以),通常会报如下错误:
- 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
错误来源代码:
net.sf.cglib.proxy.Enhancer#generateClass(ClassVisitor v)
- ......省略代码 // 以下部分的字节码,每次生成 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 出来的字节码查看则更为直观:
生成的字节码中,newInstance 方法是重复的。
dump 方法: System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");
如何处理?
实现多重代理,有一种蹩脚的方法,例如 JDK 和 Cglib 组合使用。或者你直接使用 JDK 代理。但有时候,针对类的操作还行不通。
笔者参考 Spring 的做法,实现了一个简单的多重代理。
Spring 的场景是:一个目标方法被多个 AOP 拦截,此时就需要多重代理。
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 这么复杂!!!!
简单实现 Cglib 多重代理
先说一下思路:事实上很简单,只需要再拦截器里放一个过滤器链即可,用户在过滤器里拦截多重调用。这些拦截器,就像你加 @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 结果:
转载自:https://www.cnblogs.com/stateis0/p/9744123.html