为什么cglib不代理超级调用? [英] Why does cglib not proxy super invocations?

查看:136
本文介绍了为什么cglib不代理超级调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面具有以下结构(我使用注释@Intercepted表示被拦截的方法):当我不使用而将被拦截的方法称为intercepted()时 super关键字按预期方式被称为拦截器.但是,当以以下方式调用super.intercepted()时,则永远不会调用拦截.为什么会这样?

I have following structure below (I used annotation @Intercepted to indicate the method which is intercepted): When I call intercepted method as intercepted() without using super keyword an interceptor is called as expected. However when called in the following way super.intercepted() interception is never called. Why is this the case?

public class Base {
   @Intercepted
   public void intercepted() {}
}

public class BaseImpl extends Base {    
   public void doSomething() {
     super.intercepted(); //<-- does not work
     intercepted(); //<--- without the super, it works
   }
}

推荐答案

答案就在于生成的字节码,既是Java编译器为super.methodthis.method相比生成的字节码,又是字节码.由cglib为代理生成.为了拦截方法,cglib将一个新类添加到类型层次结构中.这样,您的代理类的所有实例将具有不同的运行时类型,这是您的代理类的子类.对于您的示例,这将导致类似于以下内容的类型层次结构:

The answer lies in the generated byte code, both in the byte code generated by the Java compiler for super.method compared to this.method and in the byte code generated by cglib for the proxy. In order to intercept a method, cglib adds a new class to the type hierarchy. All instances of your proxied class will then be of a different run time type which is a subclass of your proxied class. For your example, this results in a type hierarchy similar to the following:

class Base { 
  void intercepted() { ... }
}

class BaseImpl extends Base { 
  void doSomething() { ... }
}

class BaseImpl$$cglib extends BaseImpl { 
  @Override void intercepted() { ... }
}

现在Java编译器到位了. Java编译器通过for字节代码指令之一调用方法.这些指令中的每一个都会导致不同的运行时行为.最重要的两条说明是最常见的:

Now the Java compiler comes into place. The Java compiler invokes methods by one of for byte code instructions. Each of those instructions result in a different runtime behavior. The two instructions that are important here are the most common:

  • INVOKEVIRTUAL:Java编译器将调用this.intercepted转换为动态/虚拟方法调用.作为动态调用的结果,Java运行时将查看当前类型的虚拟方法表,以便确定要调用的方法.该方法是动态绑定.这意味着,如果要从BaseImpl$$cglib实例调用intercepted,则所选方法将为BaseImpl$$cglib.intercepted.如果从类型BaseImpl$$cglib调用方法,则调用的方法将是Base.intercepted,因为BaseImpl不会覆盖intercepted.显然,Base.intercepted将调用在其自己的类中定义的方法.

  • INVOKEVIRTUAL: The invocation this.intercepted is translated into a dynamic/virtual method invocation by the Java compiler. As a consequence of a dynamic call, the Java run time will look at the current type's virtual method table in order to decide which method is to be invoked. The method is bound dynamically. This means, if you are invoking intercepted from an instance of BaseImpl$$cglib, the selected method will be BaseImpl$$cglib.intercepted. If you are invoking the method from a type BaseImpl$$cglib, the method invoked will instead be Base.intercepted because BaseImpl does not override intercepted. Obviously, Base.intercepted will invoke the method defined in its own class.

INVOKESTATIC:在运行时未动态绑定.为了调用super.intercepted,Java运行时应调用超级类型的虚拟方法表中的方法.这意味着BaseImpl将显式引用Base的方法表.结果,永远不会查询BaseImpl$$cglib的虚拟方法表,并且无法拦截调用.这与无法拦截静态方法的原因基本相同.在字节码中,静态方法和超级调用完全相同.

INVOKESTATIC: Static invocations are not bound dynamically at run time. In order to call super.intercepted, the Java run time should invoke the method of the super type's virtual method table. This means, that BaseImpl will explicitly reference the method table of Base. As a result, the virtual method table of BaseImpl$$cglib is never consulted and the calls cannot be intercepted. This is basically the same reason for which it is not possible to intercept static methods. Within byte code, static methods and super invocations are treated exactly the same.

这表示,对于super.intercepted,永远不会命中cglib代理.无法使用Java来检测已加载的类(嗯,您可以稍微推一下这个规则),这样就没有代理框架可以真正实现您的预​​期.

This said, for super.intercepted, the cglib proxy is never hit. It is not possible to instrument loaded classes in Java (well, you can push this rule a little), such that no proxy framework can actually do what you intend.

这篇关于为什么cglib不代理超级调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆