白皮书草案
警告:本文为草稿! 试图为AOP联盟制定第一个规范/指南/路线图(?)。
这里的许多想法来自ML成员之间的讨论,包括Cedric Beust,Rod Johnson,Gregor Kiczales,Bob Lee,Rickard Oberg,Andrei Popovitchi,Jon Tirsen,我自己以及其他人。
可以讨论这份草案,我希望它将有助于就AOP联盟是什么达成一个普遍而精确的观点。
介绍
本文档旨在介绍AOP联盟项目。
它的目标,理念,应该提供的答案以及不应该提供的答案。
该提案草案必须与AOP联盟的其他成员进一步讨论,以便就我们在这里所做的事情达成共识。
一旦列表上的讨论中出现了有趣的观点,它也应该完成。
本文档是白皮书,AOP联盟成员可以在内部使用,也可以为外部人员提供什么是AOP联盟的见解。
在第1部分中,我将尝试概括地解释AOP联盟的目标。
我们的动机来自于AOP可以改善诸如基于J2EE的解决方案之类的事实。
如果我们设法定义一组规范化的API,则可以将AOP集成到现有解决方案中,或使用现有AOP工具构建AOP环境。
第2部分概述了面向方面的环境的建议架构和API。我试图猜测AOP联盟应该指定哪些API。
最后,在第3节中,我将详细介绍已识别的组件及其在AOP环境中的角色。
AOP 的目标
AOP的优势:J2EE案例
面向方面的编程(AOP)是设计和编程应用程序的好方法。
与EJB之类的现有技术相比,它为许多问题提供了更好的解决方案。
J2EE是可以从AOP联盟中受益的典型目标环境(但不是唯一的)。
实际上,J2EE环境通过提供处理诸如持久性或事务之类的技术问题的手段来部分解决了一些问题。
但是,J2EE体系结构不够灵活,无法轻松添加与特定需求相关的新技术问题。
此外,能够在不需要时或优选使用轻溶剂的情况下除去一种溶液将是令人感兴趣的。
AOP提供了一种通用的方法来建立新的技术关注点(横切关注点)并将其以灵活和模块化的方式插入应用程序中。在J2EE中应用一些AOP概念也可以真正简化其使用。例如,可以使用常规Java对象(POJO)代替EJB。因此,能够轻松将完整的AOP应用于J2EE将大大提高J2EE的可用性。它还将为符合J2EE的应用服务器带来更多功能。
目前对AOP不利
AOP越来越受欢迎。
但是,大多数AOP工具的设计目的并不是要在任何环境中使用(主要是因为大多数工具都是出于实验目的而设计的)。
因此,当尝试在特定环境中使用AOP时,我们可能会遇到一些问题,因为例如,该环境已经支持某些内置方面,这些方面可能与AOP工具实现不兼容。
出现此问题是因为AOP需要修改应用程序的对象/类才能正常工作。
此对象修改逻辑是由AOP工具的特定部分实现的:编织器。
编织器可以很好地适应给定的环境,但可能会破坏另一个编织器的一些重要系统属性。
例如,在AOP联盟的Gregor和Rickard之间进行的一次有趣的讨论似乎表明,AspectJ的介绍织入实现(特定的织造操作)在某些具有某种分布和持久能力的环境中不能很好地适应。
AOP联盟索赔
这里的大多数人都不相信完美的系统。
我们认为,系统始终适合于给定的问题和环境(它不一定与其他系统相适应)。
对于我们可能在诸如J2EE之类的复杂环境中使用的AOP工具,情况就是如此。
根据所面临的问题,具有AOP的特定实现会很有用。
AOP或与AOP相关的技术已经有许多特定的实现,例如通用代理,拦截器或字节码转换器。
例如,除其他外:
AspectJ:AO源级别(和字节码级别)的编织器。新语言。
AspectWerkz:一个AO框架(XML中的字节码级动态weaver +配置)。
BCEL:字节码转换器。
JAC:AO中间件(字节码级动态织布器+配置+方面)。框架。
Javassist:具有高级API的字节码转换器。
JBoss-AOP:拦截和基于元数据的AO框架(在JBoss应用服务器上运行+独立版本)。
JMangler:字节码转换器,具有用于翻译的合成框架。
Nanning:AO编织器(框架)。
Prose:AO字节码级动态织布器(框架)。
对我们来说,这些实现反映出没有好的或坏的实现,但是适合某些问题/环境的实现。
因此,AOP联盟的目标既不是提供新的AOP模型,也不是提供适用于所有情况或在给定J2EE应用服务器上使用的出色AOP实现。
AOP联盟的目标是使所有现有实现都使用相同的核心语言,以便:
-
避免通过重用现有AOP组件来重建它们,
-
针对给定的目标环境(通常是J2EE环境)简化现有AOP组件的适应,
-
通过使用通用根AOP API简化方面的重用。
-
简化希望集成AOP功能的开发工具的实现。
面向切面架构
共同的建筑愿景
在1.2和1.3节中,我们解释说,很难就通用的AOP模型和实现达成共识,因为它与使用和环境之间的联系太紧密了(在纯Java方法和与J2EE兼容的实现中可能有所不同。方法)。
但是,我们认为有可能就面向方面的环境(AOE)达成一致的体系结构构想。
确实,在构建面向方面的环境(AOE)时,设计人员需要定义架构。
在大多数现有的AOE中,该体系结构定义并组合了一些实现系统基本功能的基本模块/组件/ API。
通过查看现有工具,我们可以确定通用组件(即在所考虑的体系结构中提供紧密功能但不必使用相同的实现技术的组件)。
例如,JBoss的编织者使用Javassist来实现一种拦截机制(在客户端侧进行检测),而JAC的编织者使用BCEL来实现一种拦截机制(在服务器侧进行检测)。
可以使用其他技术(例如,对JIT编译器进行代祷)来执行相同的效果。他们都严重依赖环境。
在下一节中,我们将尝试提取对AOE有用的组件。这些组件可用于构建上下文相关的AOE。
经典三层架构
- Figure 1: A three-layer architecture for aspect-oriented environments.
可以绘制一个典型的体系结构,如图1所示。此简化图包含一些组件(框)和一些核心逻辑(圆角框),这些逻辑可以使用(粗体箭头)组件的API。
它旨在在图的顶部运行初始AO程序。
注意,该架构并非旨在成为参考架构,而仅是一种可能的架构。
确实,存在几种构成AO体系结构的不同核心组件的可能性。
可以将这种体系结构分为三层:
一个低层(1),提供在目标平台上实现编织(AOP的主要过程)的基本组件,
一个高层(2),按其原始含义提供AOP的基本组件,以及实现AO语义的逻辑(将取决于目标平台),
开发层(3),包括最大意义上的UI(可以由一种语言支持,可以是建模工具)以及帮助开发人员信任AO程序所需的其他工具(例如类型检查),可视化工具,调试器等)。
AOP联盟应在此处指定什么?
如前所述,AOP联盟的目标不是提供新模型或更好地实现现有工具。
实际上,AOP联盟的目标是为常见面向方面的环境(AOE)实现中标识的组件指定规范化的API。
如果我们能够做到这一点,则可以通过集成最适合我们要使用AOP的上下文的组件来构建比现有AOE更好的AOE。
特别是,即使在诸如J2EE应用服务器之类的复杂环境中,也应该有可能使用最好的AOP。
因此,如果我们参考图1,则AOP联盟的作用应该是定义所标识组件的API。
最重要的组件是低级组件,因为它们的实现会影响可以使用AOE的环境。
某些技术特性也可能对所得的系统属性产生深远的影响(例如,各个方面是否可以动态地编织/非编织?
系统在分配方面是否可扩展?
系统可以与内置方面(例如持久性或事务)共存吗?)。
但是,高级组件对于诸如IDE,调试器,建模工具等工具也非常有趣。拥有通用的AOP概念操纵API将有助于工具更好地支持不同环境中的几种AOP实现。
AOP联盟可以为某些组件提供一些参考实现(通过使用现有工具)。但是,最好是现有的工具(大多数工具的创建者都在联盟中)提供自己的已定义API的实现。这些实现将验证API的正确性。
由于AOP联盟确实取决于AOE实施,因此AOP联盟不会处理编织逻辑和配置逻辑。但是,我们还应该提供一些参考实现,以显示应如何使用我们的API来构建AOE。
最后,AOP联盟将不涉及第三层(开发级别)。当他们集成的AOP工具实现我们的开发工具时,我们应该让他们使用我们的API。
AOP联盟组件
现在让我们深入了解AOP联盟核心组件的全球情况。
警告:这些组件是AOP联盟指定的API的初稿。 其中一些可能会被删除,某些可能会添加。 请注意,其中一些已经开始用Java接口指定。
低级组件
低级组件非常重要,因为整个 AOE 都依赖于它们的实现。
这些组件的实现方式至关重要,并且可能会严重影响系统的属性,例如性能,可伸缩性,集成功能或安全性。
反射
反射API对于任何AOE都是非常重要的。
实际上,编织者需要对基本程序的类进行自省,以便应用建议(advices)或引言(introductions)。
例如,如果一个切入点告诉我们应该建议一个类的所有方法(使用某种正则表达式或ALL关键字),那么编织者将需要使用反射API来明确地知道实际使用的方法列表需要建议。
当在运行时完成编织过程时,SUN的java.lang.reflect实现可能足以构建AOE。
但是,在大多数现有系统中,编织过程发生在编译时或类加载时。
在这些情况下,需要反射API的特定实现。
根据AOP联盟的说法,标准化此API以便根据AOE的运行上下文切换基础实现非常重要。
程序仪表
从编织者的角度来看,如果反射是对编织程序的读取访问,则仪器是写入访问2。
但是,在AOP中,允许的程序修改是一组简化的修改。
关于初始程序的现有结构,允许的治疗是递增的,以便可以将各个方面正确地组合在一起。
由于列表上的先前讨论,这些类型的增量修改被称为工具。
没有用于检测的标准API。
但是,就像反射一样,检测可以在运行时,编译时或加载时发生。
此外,对于每种类别,可以根据上下文和AOE的环境执行不同的实现(例如,可以直接在源代码或字节码上进行检测)。
因此,对我们来说很重要的一点是,规范化API,以便根据AOE要求更改基础实现。
拦截框架
截取框架是另一种对构建AOE极其有用的基本组件。
借助动态代理,Java 提供了用于拦截的标准 API/框架。
但是,其他实现可以实现透明度,性能等方面的多项增强(大多数实现使用工具API)。
因此,定义具有清晰语义的标准拦截API/框架也很有趣。
拦截框架具有许多优点,因为它们可以非常轻松地实现AOP模型的周围建议。
而且,它们可以是独立的,尽管使用纯Java编写,但大多数时候它们仍提供类似AOP的清晰代码。
由于这些原因,已经在许多项目和环境(包括J2EE应用服务器,请参阅JBoss)中实现了几种拦截框架。
因此,AOP联盟应该提供一个抽象的侦听框架,以便对该AOP重要工具箱进行标准化。
元数据处理
在实现AOE时,尤其是与拦截框架结合使用时,元数据处理非常有用。
它允许编织者以非侵入方式扩展类的语义。
由于元数据的大多数实现都允许动态,因此它也可以用于方面的动态配置/重新配置。
即使JDK1.5将提供元数据的标准实现,提供允许多种实现的标准API也是很有用的。
这些可能会考虑到某些环境特性,例如分发,序列化,而默认实现可能无法正确处理这些特性。
类加载框架
在许多AOE中,需要字节码级别的操作。
它可以用于实现拦截框架,或直接实现对编织程序的干预。
在某些情况下,这种字节码级别的操作可以在类的加载时完成,因为AOP工具非常简单。
因此,大多数AOE使用Java的灵活类加载架构。
但是,一些环境也使用类加载器来实现其自身的功能。
例如,分布式环境可以使用特定的类加载器来生成存根。
在这些环境中,由于类加载器不兼容,AOE的类加载机制可能导致系统崩溃。
因此,我们认为标准化一个类加载框架非常重要,该框架应具有足够的灵活性,以轻松地使来自不同环境的不同类加载器能够安全地进行协作。
高级组件
如果我们希望在第三层(开发层)中定义的工具总体上为AOP提供更好的支持,则高级组件对于规范化非常重要。
AOP API
引用 Gregor 可以很好地解释AOP API的目标:显然,我们想尽一切可能避免AOP工具之间不必要的不一致。
要真正实现标准化还为时过早,我们仍然需要有意义的差异空间。
但是不必要的差异显然值得消除。
因此,我们的AOP模型不会是一个新模型。
它将尝试将当前所有模型的共同点汇集在一起。
AspectJ模型无疑是最成功的模型,并且已经有一些工具可以支持它。
因此,我们可能会在这里使用AspectJ的一个子集。
配置 API
可以以通用方式实现许多方面。
这意味着它们实现了一种逻辑,该逻辑可用于您要在其中编织方面功能的任何程序。
在大多数情况下,这种方面重用过程意味着对通用方面进行参数化(例如,告诉通用持久性方面哪个类应该是持久性的以及如何持久化)。
在AspectJ中,这可以通过对抽象方面进行子类化来实现。
但这也可以通过使用外部工具(例如预处理器)来完成。
在J2EE环境中,内置方面的配置过程(EJB容器的技术问题)由XML部署文件进行参数化。
在JBoss / AOP和其他框架中,也可以使用XML文件来完成配置。
在JAC中,可以使用方面配置API在Java程序中完成配置,也可以使用特定于脚本的语言进行配置,依此类推。
如果我们可以标准化配置API,那就太好了。这将使开发工具的AOE集成更加容易。这也将有助于将特定配置从AOE重用到另一个(例如AspectJ和JBoss/AOP)。
请注意,将方面从AOE移植到另一个方面可能是不现实的,因为可能存在重要的差异。
但是,使方面配置可移植似乎不太现实,这已经是实现AOE互操作性的第一步。
结论
本文试图解释AOP联盟项目的原因,并指定一些目标。
我试图以名单上的许多人的名义谈论我所理解的。
目前还很不精确,只能画出全局。
也许有些人会不同意或失望。
如果我们可以进行一些非常好的讨论,以帮助我们对我们在这里真正想要的东西有好的感觉,那就太好了。