分享
 
 
 

JRockitJVM对AOP的支持,第2部分

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

前一篇文章介绍了面向方面编程和关注点分离的概念,解释了这种概念如何在方面构造的帮助下增强软件的模块化,以及如何使用它来补充面向对象编程。方面代表模块化的单元,并且由切点(何处)、建议(什么)以及类型间声明(在这个新的方面补充对象模型)组成。有许多技术可以将关注点编织进应用程序,在当今的Java领域中,最常用的技术是字节码测试,在AspectWerkz和AspectJ(从1.1版开始)中实现了这种技术。

但是,这种AOP实现方式具有几个缺点,本系列的第1篇文章对此进行了详细解释。尽管在字节码测试领域还有很大的发展余地(包括Java 5中的JVMTI/JSR-163测试代理规范和高效字节码操作库,比如ObjectWeb ASM),但字节码测试代价不菲。此外,已经证明,使用字节码测试实现AOP是不完善的。例如,如果不采用非常特殊且效率低下的解决方案,就无法通过切点匹配反射式方法调用或get和set字段。总的来说,所有基于字节码测试的产品都受到字节码测试技术相关问题的影响,而且随着这种技术的普及,问题将逐渐增加。

所有这些缺点促使JRockit团队提出了JVM对AOP的支持。其目标是尽可能全面地实现当前的AOP语义,同时不把JVM限制在某个特定的面向方面框架的语言细节和编程模型上。

本文通过具体的代码示例介绍该API,然后描述其好处及未来的发展方向。

我们的动机

让我们快速地回顾引入JVM的AOP支持的技术动机。

JVM编织是对上面提到的问题最自然的解决方案。为了说明其原因,我们将引入两个例子,它们说明JVM已经完成了编织所涉及的大多数工作:当加载一个类时,JVM读取字节码,建立为java.lang.reflect.* API进行服务所需的数据;另一个例子是方法调度。目前的JVM将方法或代码块的字节码编译为更高级、效率也更高的构造和执行流(在适用代码内联的地方进行代码内联)。由于HotSwap API的需要,JRockit JVM(可能还包括其他JVM)还会记录哪个方法调用了其他方法,因此如果在运行时重新定义某个类,那么在所有期望的位置(内联的或非内联的),类中定义的方法主体仍然可以进行热交换。

因此,不必为了编织进一个建议调用而修改字节码,比如说,在特定的方法调用之前。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将要调度的动作。动作由以下组件组成:

一个常规Java方法――我们称之为动作方法,对于每个匹配这个预定的联结点,都将调用这个方法。

一个可选的动作实例,在这个实例上调用动作方法。

一组可选的参数级注释,它们向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()抽象化相似。

下面是当前定义的注释及其含义。

[[The No.1 Picture.]]

为了支持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();

}

}

API的细节:动作实例和动作类型

正如前面代码示例中所示,动作方法可以是静态的,也可以不是。如果动作方法不是静态的,那么就必须传递一个动作实例,JVM在这个实例上调用动作方法。

其语法风格与Java开发人员使用java.lang.reflect.Method.invoke(null/*static method*/, .../*args*/)对方法进行反射式调用一样。但是,利用JVM的AOP支持,底层的动作调用根本不涉及任何反射。

允许用户控制动作实例,就会产生有趣的用例。例如,可以实现一个简单的委托模式,在运行时用另一个实现替换整个动作实例,而不涉及JVM的内部组件。

注意,这将有助于(按照规定)实现AOP方面实例化模型,比如issingleton()、pertarget()、perthis()、percflow()等等,同时不会将JVM API限制在某些预定义的语义上。

在将预定注册到编织器实例之前,赋予它一个类型作为建议类型:before、instead-of、after-returning或after-throwing。

可以编写下面这样的代码来创建预定:

// Get a Weaver instance that will act as a

// container for the subscription(s) we create

Weaver w = WeaverFactory.getWeaver();

// regular java.lang.reflect is used to refer

// to the action method "simpleStaticAction()"

Method staticActionMethod =

SimpleAction.class.getDeclaredMethod(

"simpleStaticAction",

new Class[0]//no arguments

);

MethodSub

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有