扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
作者:中国IT实验室 来源:中国IT实验室 2007年8月24日
关键字:
因此,不必为了编织进一个建议调用而修改字节码,比如说,在特定的方法调用之前。JVM实际上可以掌握关于这个建议调用的知识,它会在任何匹配的联结点上对此建议进行调度,然后再调度实际的方法。
由于不接触字节码,立即可以获得以下好处:
与JVMDI_EVENT_METHOD_ENTRY或JVMDI_EVENT_FIELD_ACCESS等JVMDI规范中定义的众所周知的C级别事件相比,这种方式有很大区别。在JVMDI中,必须首先处理C级别API,这使得它对于大多数开发人员来说有些复杂,而且难以分发。其次,规范没有提供细粒度的联结点匹配机制,而是要求预定所有这样的事件。这仍然会导致显著的开销,因此不得不进行调试。
我们的方法
我们想让您先了解一下如何在JVM中添加AOP支持。关键之处在于我们在Java API级别上提供了动作调度和预定(下面会详细描述)。因此,您可以写出下面这样的代码:
Weaver w = WeaverFactory.getWeaver();
Method staticActionMethod =SimpleAction.class.getDeclaredMethod
("simpleStaticAction",new Class[0]//no arguments);
MethodSubscription ms = new MethodSubscription
(/* where to match*/,InsertionType.BEFORE,staticActionMethod);
w.addSubscription(ms);
如您所见,我们提供了一个可访问的JVM API,可以用它来实现更传统的AOP方法。这为解决前面提到的传统AOP实现问题提供了极大的灵活性,而且也使其他使用方式成为可能。下面几节将详细介绍这个API。
动作调度和预定
JRockit JVM AOP支持公开了一个Java API,它与JVM方法调度和对象模型组件紧密集成在一起。为了确保不使JVM被限制在当前或未来的任何特定于AOP的技术方向上,我们决定实现一个动作调度和预定模型。
这个API使您能够在指定的切点上描述定义良好的预定,这样就能够注册JVM将要调度的动作。动作由以下组件组成:
动作还可以分为before动作、after returning动作、after throwing动作或者instead-of动作(类似于AOP的“around”概念)。
为了调用这个API,必须获得一个jrockit.ext.weaving.Weaver实例的句柄。这个编织器实例根据它的调用者上下文来控制允许进行哪些操作。例如,在容器级编织器可以预定特定于应用程序的联结点时,用户可能不希望部署在应用服务器中的应用程序创建编织器,从而预定某些容器级或特定于JDK的联结点的动作方法。这种编织器可见性理念反映了底层类加载器的委托模型。
我们简单介绍一下这些构造如何映射到常规的AOP构造,这有助于理解这个模型:
·预定可以视为一个有类型的联结点,或者就是一个有类型的联结点(字段get()、set()、方法call()等等),加上一个within()/withincode()切点。
·动作实例可以视为方面实例。
·动作方法可以视为建议。
熟悉AOP的读者可能已经看出,要想用这个JVM级API实现一个完整的AOP框架,还需要进行一些开发,包括一个(按照规定)管理方面实例化模型的中间层、cflow()切点的实现以及切点的完全合成和正交的实现。
API细节:动作方法
动作方法(与AOP的建议概念相似)就像(作为方面的)常规类的常规Java方法。它可以是static方法,也可以是成员方法。它的返回类型必须符合某些隐式约定,而且before动作的返回类型应该是void。对于instead-of动作(类似于AOP的around建议语义),其返回类型还是作为动作调用结果的堆栈的类型。
动作方法可以有参数,参数的注释进一步控制上下文公开,如下面的代码示例所示:
import java.lang.reflect.*;
import jrockit.ext.weaving.*;
public class SimpleAction
{ public static void simpleStaticAction()
{out.println("hello static action!");
}
public void simpleAction() {out.println("hello action!");
}
public void simpleAction(@CalleeMethod WMethod calleeM,@CallerMethod WMethod callerM)
{out.println(callerM.getMethod().getName());
out.println(" calling ");
out.println(calleeM.getMethod().getName());
}
}
该代码示例引入了jrockit.ext.weaving.WMethod类。该类用作java.lang.reflect.Method、java.lang.reflect.Constructor和类的静态初始化器(它在java.lang.reflect.*中没有出现)的包装器。这与AspectJ JoinPoint.StaticPart.getSignature()抽象化相似。
下面是当前定义的注释及其含义。
注释 |
公开 |
备注 |
@CalleeMethod |
被调用者方法(方法、构造函数、静态初始化器) |
|
@CallerMethod |
调用者方法(方法、构造函数、静态初始化器) |
|
@Callee |
被调用者实例 |
滤除静态成员调用。用作instance-of型过滤器:被调用者类型必须是所注释的参数类型的实例。 |
@Caller |
调用者实例 |
滤除来自静态成员的调用。用作instance-of型过滤器:调用者类型必须是所注释的参数类型的实例。 |
@Arguments |
调用参数 |
|
为了支持instead-of,并能够决定是否沿着截取链前进(就像在AOP中通过JoinPoint.proceed()概念实现),我们引入了jrockit.ext.weaving.InvocationContext构造,如下所示:
import jrockit.ext.weaving.*; public class InsteadOfAction { public Object instead( InvocationContext jp, @CalleeMethod Method callee) { return jp.proceed(); } }
正如前面代码示例中所示,动作方法可以是静态的,也可以不是。如果动作方法不是静态的,那么就必须传递一个动作实例,JVM在这个实例上调用动作方法。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者