概述
下来会以这个方法讲解各个概念
AspectJ(以及类似的切面编程)的动机是意识到传统编程方法不能很好地解决某些问题。考虑在某些应用程序中实施安全策略的问题。从本质上讲,安全性跨越了应用程序模块化的许多自然单元。此外,随着应用程序的发展,必须将安全策略统一应用于所有添加项。并且所应用的安全策略本身可能会发展(改变)。在传统的编程语言中,以纪律严密的方式捕获诸如安全策略之类的问题既困难又容易出错。
安全性之类的问题跨越了模块化的自然单元。对于面向对象的编程语言,模块化的自然单位就是类。但是在面向对象的编程语言中,横切的问题是不容易准确地转换成类。因为它们跨越多个类,因此它们不可重用,无法细化或继承,它们在不受约束的情况下会遍及整个程序简而言之,它们很难一起使用。
切面编程是模块化横切面的一种方式,就像面向对象的编程是一种将常见概念模块化的方式一样。 AspectJ是Java面向方面的编程的实现。
AspectJ仅仅为Java添加了一个新概念,即a join point
连接点,而这实际上只是现有Java概念的名称。它仅向Java添加了一些新的构造:pointcuts
切入点,advice
建言,类型间声明和方面inter-type declarations
, aspects
)。pointcuts
和advice
会动态影响程序流程,inter-type declarations
会静态影响程序的类层次结构,而aspects
则封装了这些新结构。
连接点join point
是程序流程中定义明确的点。切入点pointcuts
选择某些连接点和这些点的值。一个建言advice
是在到达连接点时执行的代码。这些是AspectJ的动态部分。
AspectJ还具有不同类型的类型间声明inter-type declarations
,这些声明允许程序员修改程序的静态结构,即程序的类的成员和类之间的关系。
AspectJ的切面aspects
是横切关注点的模块化单位。它们的行为有点像Java类,但也可能包括切入点,建言和类型间声明。
在紧随其后的各节中,我们将首先研究连接点以及它们如何组成切入点
。然后,我们将查看advice
,即到达切入点时运行的代码。我们将看到如何将切入点
和建言
组合到AspectJ的可重用,可继承的模块化单元切面aspect
。最后,我们将研究如何使用类型间声明来处理程序的类结构的横切关注点。
tips:术语:
连接点:join point 。方法和类之间的空隙
切入点:pointcuts。目标空隙
建言:advice。命中目标空隙
时执行的代码
类型间声明:nter-type declarations。多重类型声明,可以改变类结构(增减构造器、方式、filed)
切面:aspect。 就想class对于oop,这是aop的航空母舰
动态切点模型
The Dynamic Join Point Model
连接点模型是任何面向方面的语言设计中的关键要素。连接点模型提供了共同的参考框架,从而可以定义横切关注点的动态结构。本章描述AspectJ的动态连接点,其中连接点是程序执行中某些明确定义的点。
AspectJ提供了多种连接点,但是本章仅讨论其中一种:方法调用连接点。方法调用连接点包含对象接收方法调用的操作。它包括构成方法调用的所有操作,从对所有参数进行评估直到返回(包括返回或正常返回或引发异常)开始。
运行时的对每个方法的调用都被定义为不同的连接点,即使它们来自程序的同一个定义(理解为定义和实例的关系)。调用一个方法连接点时,会有很多连接点在方法体中被调用。我们就称这些方法在原始的调用连接点的动态上下文中( dynamic context)执行
上下文可以理解为原始方法的关联环境。
pointscuts
切点。在AspectJ,pointcuts
承载具体 的Join points。
比如这个crosscut类型-- call(void Point.setX(int))
就负责捕获void Point.setX(int)
一个pointcut由多个crosscut组成(&&,||,!
)。
一个pointcut的声明格式
这个move()
可以捕获5个crosscut。
上面的这个pointcut基于一系列方法签名的枚举,我们称之为name-based
切面。
Aspect也提供一些基于方法属性的切面property-based
切面。
-
call(void Figure.make*(…))
捕获make开头的方法 -
call(public * Figure.* (…))
捕获Figure的所有public 方法 -
除了通配符,还提供其他方式比如
cflow(move())
: 假如你想捕获在程序控制流程内遇到的所有连接点,这些连接点都在某一个特定的连接点之后,你可以考虑使用cflow。
advice
建言是定义切点的行为。
AspectJ有几种不同的建言。
Before advice
是到达连接点之前发生。
before(): move() {
System.out.println("about to move");
}
after advice
在一个方法执行某些(returning
,throwing
)关键点之后。单纯的after
的两个点之后。
after() returning: move() {
System.out.println("just successfully moved");
}
Around advice
也可以在线程前,也可以在线程后。
after() returning: move() {
System.out.println("just successfully moved");
}
暴露pointcuts的context
可以获取jointpoint的内容。
- 格式如下
用三个暴露的context, 一个FigureElement named fe、 ints named x and y - body使用
this
、target
、和args
这三个原始的pointcuts用来修饰values,修饰是用&&
的关系。call 是 this,target把figureElement修饰为 fe。args(x,y)是指 int x,int y。- 将
this
、target
、和args
定义为pointcut
将上一个例子抽出来单独定义
Inter-type declaratios
AspectJ中的内置类型
可以跨越多个类和结构。不像advice是动态的,内置类型作用在编译阶段。
- 问题
考虑一下为一堆已存在的类共享的问题添加一个新功能的问题(这些类有关联,是集成关系)。在java中,先创建一个接口来捕获这个新功能,然后为每一个被影响的类添加这个接口的实现。 - AspectJ的解决办法
AspectJ可以在一个地方来解决,通过使用inter-type
声明。这个aspect
声明了实现新能几个必要的方法和域,并关联这些域和方法到已经存在类。 - 举例
假定我们有screen
对象来监视一堆Point
对象。我们可以通过实现一个aspect
声明point
有一个变量observers
,来实现这个Screen
对Point
s的监视。
该处定义了Point有个私有变量observers。observers是private
修饰的,所以只有PointObserving
可以看见他,。加两静态方法在这个切面上,来添加或移除Screen
沿着这个思路,我们定义一个切点changes
–定义了我们想要观察的,和after advice
定义了当观察到这个change后的我们该做的动作
pointcut
起名做changes(Point p),target锁定p对象,在执行set*方法时触发
after
定义在set方法之后调用UpdateOberver向每个屏幕更新。
aspects
aspect包装了pointcuts,advice,和inter-type 在一个横切的实现处。它的定义非常像一个class,有methods,fields。
像类,切面可以被实例化,但是AspectJ的实例化不能用new
,默认的每个aspectJ
是一个单例。意味着advice也许用non-static的域。如下用logStream 保留System.err。