使用CGLIB在Spring中创建嵌套代理

huangapple go评论143阅读模式
英文:

Nested Proxy using cglib in spring

问题

前言:我想要创建一个已存在代理的代理(使用Spring中的cglib包),就像在我调用原始方法类时,两个代理的方法都会首先被调用。这有任何意义吗?或者可行吗?

问题:当我创建第二个enhancer时,我会得到java.lang.ClassFormatError-->Duplicate method name "newInstance" with signature "异常。

##示范代码如下

###原始类

public class OriginalClass {
    
    public void print(){
        System.out.println("MAIN METHOD");
    }
    
}

###创建两个代理

public class Main {

    public static void main(String[] args) {

        //创建第一个代理
        Enhancer firstEnhancer = new Enhancer();
        firstEnhancer.setSuperclass(OriginalClass.class);
        firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
            return methodProxy.invokeSuper(o, objects);
        });
        OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();

        //创建第二个代理
        Enhancer secondEnhancer = new Enhancer();
        secondEnhancer.setSuperclass(firstProxy.getClass());
        secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
            return methodProxy.invokeSuper(o, objects);
        });

        //在这一行出现异常
        OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();

        //调用
        secondProxy.print();
    }
}

###预期结果如下(打印)

METHOD INTERCEPTOR AT SECOND PROXY
METHOD INTERCEPTOR AT FIRST PROXY
MAIN METHOD

###但我得到了以下异常(在创建第二个代理时)

Caused by: java.lang.ClassFormatError: Duplicate method name "newInstance" with signature "([Lorg.springframework.cglib.proxy.Callback;)Ljava.lang.Object;" in class file com/test/OriginalClass$$EnhancerByCGLIB$$37b306ed$$EnhancerByCGLIB$$15133919

实际场景

我想要在所有被Spring代理的bean上创建一个代理,使用BeanPostProcessorscglib。例如,我想要在所有@Transactional方法上创建一个代理(在事务之前和之后进行日志记录)。

更新:我更喜欢创建代理,而不是AOP(AOP本身就是代理)。

英文:

Preface: I want to create a proxy of an existed proxy (Using cglib package in spring)
, like when I call the original method class both methods of both proxies called first. Does it make any sense at all? or is it possible?

Problem: When I'm creating the second enhancer, i get the
java.lang.ClassFormatError-->Duplicate method name "newInstance" with signature " exception.


##Sample code is as follows

###Original Class

public class OriginalClass {
    
    public void print(){
        System.out.println("MAIN METHOD");
    }
    
}

###Create Two Proxies

public class Main {

    public static void main(String[] args) {

        //Create First Proxy
        Enhancer firstEnhancer= new Enhancer();
        firstEnhancer.setSuperclass(OriginalClass.class);
        firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
            return methodProxy.invokeSuper(o, objects);
        });
        OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();

        //Create Second Proxy
        Enhancer secondEnhancer= new Enhancer();
        secondEnhancer.setSuperclass(firstProxy.getClass());
        secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
            return methodProxy.invokeSuper(o, objects);
        });

        //Getting Exception on this line
        OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();

        //Call 
        secondProxy.print();
    }
}

###The expected result is as follows (Print)

METHOD INTERCEPTOR AT SECOND PROXY
METHOD INTERCEPTOR AT FIRST PROXY
MAIN METHOD

###But I get the below Exception (when creating the second proxy)

Caused by: java.lang.ClassFormatError: Duplicate method name "newInstance" with signature "([Lorg.springframework.cglib.proxy.Callback;)Ljava.lang.Object;" in class file com/test/OriginalClass$$EnhancerByCGLIB$$37b306ed$$EnhancerByCGLIB$$15133919

###Real World Scenario
I want to wrap a proxy on all beans that have been proxied by spring, using BeanPostProcessors and cglib . For example, I want to wrap a proxy on all @transactional methods (log before and after the transactions).

Update: I prefer to create proxies, not AOPs.(AOP is itself a proxy)

答案1

得分: 3

我已找到可行的解决方案,在第二个增强器中使用 methodProxy.invoke() 而不是 methodProxy.invokeSuper(),同时在调用中将 firstProxy 传递给调用,而不是 o 对象,并且将 superClass 设置为原始的那个,该类没有 newInstance 方法:

public class Test {
    public static void main(String[] args) {

        // 创建第一个代理
        Enhancer firstEnhancer = new Enhancer();
        firstEnhancer.setSuperclass(OriginalClass.class);
        firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("第一个代理的方法拦截器");
            return methodProxy.invokeSuper(o, objects);
        });
        OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();

        // 创建第二个代理
        Enhancer secondEnhancer = new Enhancer();
        secondEnhancer.setSuperclass(firstProxy.getClass().getSuperclass());
        // secondEnhancer.setSuperclass(OriginalClass.class);
        secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("第二个代理的方法拦截器");
            return methodProxy.invoke(firstProxy, objects);
        });

        // 在这一行出现异常
        OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();

        // 调用方法
        secondProxy.print();
    }
}

输出结果:

第二个代理的方法拦截器
第一个代理的方法拦截器
主方法
英文:

I've found working soultion, it works when used methodProxy.invoke() instead of methodProxy.invokeSuper() in the second enhancer, also the firstProxy need to be passed to the invocation instead of the o object and the superClass is set to the original one, that doesn't have the newInstance method:

public class Test {
	 public static void main(String[] args) {

	        //Create First Proxy
	        Enhancer firstEnhancer= new Enhancer();
	        firstEnhancer.setSuperclass(OriginalClass.class);
	        firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
	            System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
	            return methodProxy.invokeSuper(o, objects);
	        });
	        OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();

	        //Create Second Proxy
	        Enhancer secondEnhancer= new Enhancer();
            secondEnhancer.setSuperclass(firstProxy.getClass().getSuperclass());
	        // secondEnhancer.setSuperclass(OriginalClass.class);
	        secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
	            System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
	            return methodProxy.invoke(firstProxy, objects);
	        });

	        //Getting Exception on this line
	        OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();

	        //Call 
	        secondProxy.print();
	    }
}

result:

METHOD INTERCEPTOR AT SECOND PROXY
METHOD INTERCEPTOR AT FIRST PROXY
MAIN METHOD

huangapple
  • 本文由 发表于 2020年3月15日 15:42:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/60690702.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定