扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年8月24日
关键字:
某些其他情况可能导致更加无法预测的结果。例如,当一个字段访问被截取时,这往往意味着字段获取(field get)字节码指令被移动到一个新添加的方法,并且被替换为对这个新方法的调用。因此,下一个编织器将在代码中的另一个位置(在那个新添加的方法中)看到一个字段访问,而它自己的匹配机制和配置可能不匹配这个位置。
总之,主要问题如下:
截取反射式调用是不可能的
当前的编织方式只能测试(至少是部分地)可静态确定的执行流。请考虑以下代码示例,它在给定的实例foo上调用方法void doA()。
public void invokeA(Object foo) throws Throwable { Method mA = foo.getClass().getDeclaredMethod("doA",
new Class[0]); mA.invoke(foo, new Object[0]); }
在现代的代码库中常常使用这种反射式访问来创建实例、调用方法或者访问字段。
从字节码的角度来看,对方法void doA()的调用是看不到的。编织器只看到对java.lang.reflect API的调用。还没有简单且高效的办法可以对通过反射执行的调用进行编织。目前,这对于如何执行编织以及如何实现AOP是很重要的限制。最好的办法是,开发人员使用执行端切点来代替。显然,从JVM的角度来看,存在一个对doA()方法的方法调度,尽管这在源代码或字节码中没有出现。已经证明,JVM编织是以高效的方式解决这个问题的唯一编织机制。
其他问题
某些人对字节码测试持怀疑态度,尤其是在动态执行的情况下(在装载时或运行时)。对于动态修改代码,存在着一种不应低估的情绪化影响,尤其是在与某种盲目的革命性新技术(比如AOP或服务的透明式插入)结合使用时。在涉及多个代理时可能发生的混乱将增加人们的怀疑。
另一个潜在的问题是Java规范中对类文件规定的64Kb边界。方法体的字节码指令总长度被限制为64Kb。在编织已经很大的类文件(例如,将JSP文件编译为servlet时产生的类文件)时,这可能会导致问题。在处理这个类时,可能会突破64Kb的限制,这就会导致运行时错误。
提议的解决方案
对于上面讨论的大多数问题,JVM编织是自然的解决方案。为了理解其原因,我们将查看两个示例。这些示例说明,JVM已经做了执行编织所需的大多数工作:当类被装载时,JVM读取字节码以便建立为java.lang.reflect.* API服务所需的数据。另一个例子是方法调度。现代的JVM将方法或代码块的字节码编译为更高级而且更高效的构造和执行流(在可以应用代码内联的地方进行代码内联)。由于HotSwap API的需要,JRockit JVM(可能还包括其他JVM)还会记录哪个方法调用了其他方法,这样如果在运行时重新定义某个类,那么在所有期望的位置(内联的或非内联的),类中定义的方法体仍然可以被热交换。
因此,不必为了编织进一个建议调用而修改字节码,比如说在特定的方法调用之前。JVM实际上可以掌握关于这个建议调用的知识,它会在任何匹配的联结点上对此建议进行调度,然后再调度实际的方法。
由于不接触字节码,可以预期到直接的好处,比如:
本系列的第二篇文章将详细描述提议的JRockit JVM对AOP的支持。
以下代码示例作了总结性说明。它在调用sayHello()方法之前对静态方法advice()进行调度:
public class Hello { // -- the sample method to intercept public void sayHello() { System.out.println("Hello World"); } // -- using the JRockit JVM support for AOP static void weave() throws Throwable { // match on method name StringFilter methodName = new StringFilter( "sayHello", StringFilter.Type.EXACT ); // match on callee type ClassFilter klass = new ClassFilter( Hello.class, false, null ); // advice is a regular method dispatch Method advice = Aspect.class.getDeclaredMethod( "advice", new Class[0] ); // get a JRockit weaver and subscribe the // advice to the join point picked out by the filter Weaver w = WeaverFactory.createWeaver(); w.addSubscription(new MethodSubscription( new MethodFilter( 0, null, klass, methodName, null, null ), MethodSubscription.InsertionType.BEFORE, advice )); } // -- sample code static void test() { new Hello().sayHello(); } public static void main(String a[]) throws Throwable { weave(); test(); } // -- the sample aspect public static class Aspect { public static void advice() { System.out.println("About to say:"); } } }
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者