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

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

Nested Proxy using cglib in spring

问题

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

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

##示范代码如下

###原始类

  1. public class OriginalClass {
  2. public void print(){
  3. System.out.println("MAIN METHOD");
  4. }
  5. }

###创建两个代理

  1. public class Main {
  2. public static void main(String[] args) {
  3. //创建第一个代理
  4. Enhancer firstEnhancer = new Enhancer();
  5. firstEnhancer.setSuperclass(OriginalClass.class);
  6. firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  7. System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
  8. return methodProxy.invokeSuper(o, objects);
  9. });
  10. OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();
  11. //创建第二个代理
  12. Enhancer secondEnhancer = new Enhancer();
  13. secondEnhancer.setSuperclass(firstProxy.getClass());
  14. secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  15. System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
  16. return methodProxy.invokeSuper(o, objects);
  17. });
  18. //在这一行出现异常
  19. OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();
  20. //调用
  21. secondProxy.print();
  22. }
  23. }

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

  1. METHOD INTERCEPTOR AT SECOND PROXY
  2. METHOD INTERCEPTOR AT FIRST PROXY
  3. MAIN METHOD

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

  1. 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

  1. public class OriginalClass {
  2. public void print(){
  3. System.out.println("MAIN METHOD");
  4. }
  5. }

###Create Two Proxies

  1. public class Main {
  2. public static void main(String[] args) {
  3. //Create First Proxy
  4. Enhancer firstEnhancer= new Enhancer();
  5. firstEnhancer.setSuperclass(OriginalClass.class);
  6. firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  7. System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
  8. return methodProxy.invokeSuper(o, objects);
  9. });
  10. OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();
  11. //Create Second Proxy
  12. Enhancer secondEnhancer= new Enhancer();
  13. secondEnhancer.setSuperclass(firstProxy.getClass());
  14. secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  15. System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
  16. return methodProxy.invokeSuper(o, objects);
  17. });
  18. //Getting Exception on this line
  19. OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();
  20. //Call
  21. secondProxy.print();
  22. }
  23. }

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

  1. METHOD INTERCEPTOR AT SECOND PROXY
  2. METHOD INTERCEPTOR AT FIRST PROXY
  3. MAIN METHOD

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

  1. 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 方法:

  1. public class Test {
  2. public static void main(String[] args) {
  3. // 创建第一个代理
  4. Enhancer firstEnhancer = new Enhancer();
  5. firstEnhancer.setSuperclass(OriginalClass.class);
  6. firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  7. System.out.println("第一个代理的方法拦截器");
  8. return methodProxy.invokeSuper(o, objects);
  9. });
  10. OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();
  11. // 创建第二个代理
  12. Enhancer secondEnhancer = new Enhancer();
  13. secondEnhancer.setSuperclass(firstProxy.getClass().getSuperclass());
  14. // secondEnhancer.setSuperclass(OriginalClass.class);
  15. secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  16. System.out.println("第二个代理的方法拦截器");
  17. return methodProxy.invoke(firstProxy, objects);
  18. });
  19. // 在这一行出现异常
  20. OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();
  21. // 调用方法
  22. secondProxy.print();
  23. }
  24. }

输出结果:

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

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:

  1. public class Test {
  2. public static void main(String[] args) {
  3. //Create First Proxy
  4. Enhancer firstEnhancer= new Enhancer();
  5. firstEnhancer.setSuperclass(OriginalClass.class);
  6. firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  7. System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
  8. return methodProxy.invokeSuper(o, objects);
  9. });
  10. OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();
  11. //Create Second Proxy
  12. Enhancer secondEnhancer= new Enhancer();
  13. secondEnhancer.setSuperclass(firstProxy.getClass().getSuperclass());
  14. // secondEnhancer.setSuperclass(OriginalClass.class);
  15. secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
  16. System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
  17. return methodProxy.invoke(firstProxy, objects);
  18. });
  19. //Getting Exception on this line
  20. OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();
  21. //Call
  22. secondProxy.print();
  23. }
  24. }

result:

  1. METHOD INTERCEPTOR AT SECOND PROXY
  2. METHOD INTERCEPTOR AT FIRST PROXY
  3. 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:

确定