AOP二世  基于AspectJ和Schema的AOP

目录

AspectJ形式的Spring AOP

@AspectJ形式AOP使用之先睹为快

编程方式织入

通过自动代理织入

@AspectJ形式的Pointcut

@AspectJ形式Pointout的声明方式

@AspectJ形式Pointcut表达式的标志符

execution

within

this和target

args

@within

@target

@args

@annotation

@AspectJ形式的Polntcut在Spring AOP中的真实面目

@AspectJ形式的Advice

Before Advice

After Throwing Advice

After Returning Advice

After (Finally) Advice

Around Advice

Introduction

 @AspectJ中的Aspect更多话题

Advice的执行顺序

Aspect的实例化模式

基于Schema的AOP

基于Schema的AOP配置概览

向基于Schema的AOP迁移

单纯的迁移

深入挖掘 aop advisor 

 @AspectJ到“基于Schema的AOP"迁移

基于Schema的Aspect声明

基于Schema的Pointcut

基于Schema的Advice声明

Before Advice

After Returning Advice

After Throwing Advice

After (Finally) Advice

Around Advice

Introduction

Advice的参数化

Advice的执行顺序

Aspect的实例化模式


AspectJ形式的Spring AOP

Spring框架2.0版本发布之后,Spring AOP增加了新的特性,或者说增加了新的使用方式。

支持AspectJ5发布的@AspectJ形式的AOP实现方式。现在,我们可以直接使用POJO来定义 Aspect以及相关的Advice, 并使用一套标准的注解标注这些POJO。Spring AOP会根据注解信 息查找相关的Aspect定义,并将其声明的横切逻辑织入当前系统。

简化了的XML配置方式。现在,使用新的基于XSD的配萱方式,我们可以使用aop独有的命名 空间,并且注册和使用POJO形式实现的AOP概念实体。因为引入了AspectJ的Pointcut描述语言, 也可以在新的配置方式中使用AspectJ形式的Pointcut表达式

但这只是从使用的角度来看。如果从更“本质”一点儿的角度进行分析的话,我们会发现当升级到 2.0版本之后,实际上如下两点是最主要的。

可以使用POJO声明AspectJ相关的Advice, 而再也不用像1.x版本中那样,要实现特定的Advice 就需要实现规定的接口。

获得了新的Pointcut表述方式,因为现在引入了AspectJ的Pointcut语言,再也不用在“直接 指定方法名”还是“使用正则表达式”之间选择了。至于说基于XSD的简化的配置方式,应该算 是锦上添花之作。

虽然2.0之后的SpringAOP集成了AspectJ, 但实际上只能说是仅仅拿来AspectJ的“皮大衣“用一下。

而底层各种概念的实现以及织入方式,依然使用的是Spring1.x原先的实现体系。这就好像我们中国人 说中国话,而英语在世界上较为普及并且有范围较广的影响力,我们可以学习英语,把英语拿过来为 我所用,但本质上,我们还是中国人,而不是英国人。换句话说,Spring AOP还是Spring AOP, 只不 过多学了门外语而已。

下面让我们看一下当Spring AOP拥有了AspectJ这种表达能力之后,同样的话该怎么来说吧!

@AspectJ代表一种定义Aspect的风格,它让我们能够以POJO的形式定义Aspect, 没有其他接口定 义限制。唯一需要的,就是使用相应的注解标注这些Aspect定义的POJO类。之后,SpringAOP会根据 标注的注解搜索这些Aspect定义类,然后将其织入系统。

这种方式是从AspectJ所引入的,定义的Aspect类基本上可以在SpringAOP和AspectJ之间通用。不 过,SpringAOP只使用AspectJ的类库进行Pointcut的解析和匹配,最终的实现机制还是SpringAOP最初的架构,也就是使用代理模式处理横切逻辑的织入。

下面我们来看看@AspectJ形式是如何使用的!

@AspectJ形式AOP使用之先睹为快

如果将之前的PerformanceMethodInterceptor定义的横切逻辑以@Aspect形式实现,首先得定义一个Aspect,以最普通的POJO来定义这个Aspect就可以。按照@Aspect形式重构后的Performance MethodInterceptor定义,如代码清单所示。

定义这么一个Aspect, 我们再也无需像1.x时代的SpringAOP那样实现相应的接口了,现在唯一要 做的就是为这个Aspect类加上一个@Aspect的注解。这样,稍后我们可以根据这个@Aspect, 来判断 Classpath中哪些类是我们要找的Aspect定义。

我们知道,Aspect中可以定义多个Pointcut以及多个Advice, 所以,除了要使用@Aspect标注Aspect 类之外,还需要通过名为@Pointcut的注解指定Pointcut定义,通过@Around等注解来指定哪些方法定 义了相应的Advice逻辑。至于说这些注解如何使用,以及对应的方法定义还有什么需要注意的地方, 我们先不要管,稍后会详细讲述。

假设我们有如下目标对象类定义:

现在有两种方式将Aspect定义织入这个目标对象类,实现对其符合Pointcut定义的Joinpoint (也就 是方法执行)进行拦截。

编程方式织入

还记得在讲解Proxy Factory的时候,除了ProxyFactoryBean, 我们还提到ProxyFactory的另 一个“兄弟”吗?对,那就是org.springframework.aop.aspectj.annotation.AspectJProxy­Factory。

通过AspectJProxyFactory. 我们就可以实现Aspect定义到目标对象的织入,这样就有了如下代 码所示的编程方式织入过程:

AspectJProxyFactory的使用与ProxyFactory没有多大差别,只不过多了addAspect ()方法, 通过该方法可以直接为AspectJProxyFactory添加相应的Aspect定义。实际上,如果我们愿意,完全 可以把AspectJProxyFactory当作ProxyFactory来用!

通过自动代理织入

针对@AspectJ风格的AOP, Spring AOP专门提供了一个AutoProxyCreator实现类进行自动代理, 以免去过多编码和配置的工作,这个AutoProxyCreator我们之前也提到过,即org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。它是在Abstract­Advisor AutoProxyCreator的基础上给出的一个扩展类,它的直接父类是AspectJAwareAdvisor­AutoProxyCreator。

与使用其他AutoProxyCreator一样,我们只需要在loC容器的配置文件中注册一下AnnotationAwareAspectJAutoProxyCreator就可以了,如下配置所示:

现在,AnnotationAwareAspectJAutoProxyCreator会自动搜集IoC容器中注册的Aspect, 并应 用到Pointcut定义的各个目标对象上。如果我们通过容器取得现在的target对象的话,会发现它已经 是被代理过的了,如下:

当然,如果把target作为依赖对象注入其他的bean定义,那么依赖的主体对象现在持有的也是被 代理过的目标对象。

刚才AnnotationAwareAspectJAutoProxyCreator注册到容器的方式是基于DTD的配置方式, 在Spring 1.x以及2.x版本中都可以使用。如果我们能够使用Spring 2.x版本,井且使用基于XSD的配置 方式,还可以有另一种更加简洁的配置方式,如代码清单所示。

通过面向aop命名空间的<aop:aspectj-autoProxy>,可以达到与基于DtD的配置方式中,直接声 明AnnotationAwareAspectJAutoProxyCreator相同的效果。

该元素背后的工作实际上就是由AnnotationAwareAspectJAutoProxyCreator做的。另外,不要忘了将aop命名空间的Schema定义引入XSD定义。我想,要用<aop:aspectj-autoproxy>的话,应该也不会忘记这一点!

小心 在使用@AspectJ形式的AOP的时候,应该尽量使用容器内的自动代理支持.通常,只 有出于测试目的,才会使用编程的方式进行直接的织入操作令在使用的过程中,你会发现,实 际上这两种织入方式是有差异的,一些行为并不统一.

从现在开始,只要使用到了@Aspect形式的AOP, 就不要忘记将aspectjweaver. jar和 aspectjrt. jar加入到应用程序的Classpath中。因为有些具体工作是要求助于AspectJ的类库的,要知 道都哪些具体任务,我们接着往下行吧!

@AspectJ形式的Pointcut

在Spring框架发布2.0版本之前,SpringAOP没有像AspectJ那样的正式的Pointcut描述语言,而且也 只支持方法级别的拦截。所以通常情况下,简单的方法名指定以及正则表达式两种方式,基本可以很 好地达到目的。在Spring发布2.0版本之后,SpringAOP框架集成了AspectJ的部分功能,这其中就包括 AspectJ的Pointcut描述语言支持。

@AspectJ形式Pointout的声明方式

@AspectJ形式的Pointcut声明,依附在@Aspect所标注的Aspect定义类之内,通过使用 org .aspectj. lang. annotation. Pointcut这个注解,指定AspectJ形式的Poincut表达式之后,将这 个指定了相应表达式的注解标注到Aspect定义类的某个方法上即可。代码清单给出了一个使用 pointcut的简单示例。

@AspectJ形式的Pointcut声明包含如下两个部分。

Pointcut Expression。Pointcut Expression的载体为pointcut, 该注解是方法级别的注解,所以, Pointcut Expression不能脱离某个方法单独声明。Pointcut Expression附着于上的方法称为该 Pointcut Expression的Pointcut Signature。

Pointcut Expression是真正规定Pointcut匹配规则的地 方,可以通过@Pointcut直接指定AspectJ形式的Pointcut。@Pointcut所指定的AspectJ形 式的Pointcut表达式由如下两部分组成。

Pointcut标志符(Pointcut Designator)。标志符表明该Pointcut将以什么样的行为来匹配表达 式,可以使用的Pointcut表达式将在后文中详细讲述。

表达式匹配模式。在Pointcut标志符之内可以指定具体的匹配模式

Pointcut Signature。Pointcut Signature在这里具体化为一个方法定义,它是Pointcut Expression 的载体。Pointcut Signature所在的方法定义,除了返回类型必须是void之外,没有其他限制。

方法修饰符所起的作用与Java语言中语义相同,public型的Pointcut Signature可以在其他 Aspect定义中引用,private则只能在当前Aspect定义中引用。可以将Pointcut Signature作为相 应Pointcut Expression的标志符,在Pointcut Expression的定义中取代重复的Pointcut表达式定义, 如代码清单所示。

stillMehtod1Execution ()的Pointcut expression, 通过第一个Pointcut定义的Pointcut Signature, 即method1Execution(}, 引用了第一个Pointcut定义,所以,这两个Pointcut定义的规则是一样的。

AspectJ的Pointcut表达式支持通过&&,||,以及!逻辑运算符,进行Pointcut表达式之间的逻辑运算, 运算符可以应用于具体的Pointcut表达式,以及相应的Pointcut Signature。代码清单演示了这几种 逻辑运算符的使用。

可以看到,通过前两个简单的Pointcut定义以及相应的逻辑运算,可以得到更为复杂的Pointcut定 义。因为前两个简单的Pointcut定义只需要在当前Aspect内引用,所以,我们声明为private。不过, 我们也完全可以将其声明为public型的,这样,其他的Aspect中的Pointcut定义也同样可以引用的到。 对于一个系统中能够公用或者统一管理的一类Pointcut来说,完全可以声明一个专门的Aspect来定义这 些Pointcut, 如代码清单所示。

然后,在其他Aspect定义的Pointcut定义中引用它们,以避免重复定义,比如:

为了能够让Pointcut表达式能够运行起来,我们还是抓紧时间来看一下都有哪些可以使用的 Pointcut标志符吧!

@AspectJ形式Pointcut表达式的标志符

虽然AspectJ的Pointcut:可用的标志符很丰富,基本上可以囊括所有Joinpoint类型的表述,但 是,因为Spring AOP只支持方法级别的Joinpoint, 所以可以通过AspectJExpressionPointcut指定的AspectJ形式的Pointcut:是有一定限制的,我们只能使用AspectJ的Pointcut表述语言中的少数几种 标志符。

execution

Spring AOP仅支持方法执行类型的Joinpoint, 所以execution将会是我们使用最多的标志符,使 用它,将帮助我们匹配拥有指定方法签名的Joinpoint。使用execution标志符的Pointcut表达式的规定 格式如下:

其中,方法的返回类型、方法名以及参数部分的匹配模式是必须指定的,其他部分的匹配模式可以省略

假设我们拥有以下类定义:

那么可以使用如下的Pointcut表达式来匹配Foo的doSomething的方法执行:

execution{public void Foo.doSomething{String))

因为部分匹配模式可以省略,所以,我们也可以简化以上模式,如下所示:

execution{void doSomething(String))

除此之外,我们还可以在execution的表达式中使用两种通配符,即*和..

*可以用于任何部分的匹配模式中,可以匹配相邻的多个字符,即一个Word。使用*之后,我 们以上的execution表达式就可以简化成:

当然这样的简化之后,匹配的范围要比原来的表达式所匹配的范围要广得多。另外,我们还 可以在方法参数匹配模式中也使用*来匹配,如下所示:

在这里,以上表达式表示只有一个参数的方法,参数类型可以为任何类型。

..通配符可以在两个位置使用,一个是在declaring-type-pattern规定的位置,一个在方法 参数匹配模式的位置。如果用于declaring-type-pattern规定的位置,则可以指定多个层次 的类型声明,如下:

如果..用于方法参数列表匹配,则表示该方法可以有0到多个参数,参数类型不限,如下:

注意,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值