第10章 Spring AOP二世
本章内容
- @AspectJ形式的Spring AOP
- 基于Schema的AOP
@AspectJ形式的Spring AOP
Spring框架2.0版本发布之后,SpringAOP增加了新的特性,或者说增加了新的使用方式。
-
支持AspectJ5发布的
@AspectJ
形式的AOP实现方式。现在,我们可以直接使用POJO来定义Aspect以及相关的Advice,并使用一套标准的注解标注这些POJO。SpringAOP会根据注解信息查找相关的Aspect定义,并将其声明的横切逻辑织入当前系统。 -
简化了的XML配置方式 。现在,使用新的基于XSD的配置方式,我们可以使用aop独有的命名空间,并且注册和使用POJO形式实现的AOP概念实体。因为引入了AspectJ的Pointcut描述语言,也可以在新的配置方式中使用AspectJ形式的Pointcut表达式。但这只是从使用的角度来看。
如果从更“本质”一点儿的角度进行分析的话,我们会发现当升级到2.0版本之后,实际上如下两点是最主要的。
-
可以使用POJO声明Aspect和相关的Advice ,而再也不用像1.x版本中那样,要实现特定的Advice就需要实现规定的接口。
-
获得了新的Pointcut表述方式 ,因为现在引入了AspectJ的Pointcut表述语言,再也不用在“直接指定方法名”还是“使用正则表达式”之间选择了。至于说基于XSD的简化的配置方式,应该算是锦上添花之作。
虽然2.0之后的SpringAOP集成了AspectJ,但实际上只能说是仅仅拿来AspectJ的“皮大衣”用一下。而底层各种概念的实现以及织入方式,依然使用的是Spring1.x原先的实现体系。这就好像我们中国人说中国话,而英语在世界上较为普及并且有范围较广的影响力,我们可以学习英语,把英语拿过来为我所用,但本质上,我们还是中国人,而不是英国人。换句话说,SpringAOP还是SpringAOP,只不过多学了门外语而己。下面让我们看一下当SpringAOP拥有了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就可以。
按照@AspectJ
形式重构后的PerformanceMethoaInterceptor
定义,如下方代码所示。
定义这么一个Aspect,我们再也无需像1.x时代的SpringAOP那样实现相应的接口了,现在唯一要做的就是为这个Aspect类加上一个Aspect的注解。这样,稍后我们可以根据这个@Aspect
,来判断Classpath中哪些类是我们要找的Aspect定义。
我们知道,Aspect中可以定义多个Pointcut以及多个Advice,所以,除了要使用@Aspect
标注Aspect类之外,还需要通过名为@Pointcut
的注解指定Pointcut定义,通过@Around
等注解来指定哪些方法定义了相应的Advice逻辑。
至于说这些注解如何使用,以及对应的方法定义还有什么需要注意的地方,我们先不要管,稍后会详细讲述。
假设我们有如下目标对象类定义:
现在有两种方式将Aspect定义织入这个目标对象类,实现对其符合Pointcut定义的Joinpoint(也就是方法执行)进行拦截。
1. 编程方式织入
还记得在讲解 ProxyFactory
的时候,除了 ProxyFactoryBean
,我们还提到 ProxyFactory
的另一个“兄弟”吗?对,那就是 org.springframework.aop.aspectj.annotation.AspectJProxyFactory
。
通过 AspectJProxyFactory
,我们就可以实现 Aspect 定义到目标对象的织入,这样就有了如下代码所示的编程方式织入过程:
AspectJProxyFactory
的使用与ProxyFactory
没有多大差别,只不过多了addAspect()
方法,通过该方法可以直接为AspectJProxyFactory
添加相应的Aspect定义。实际上,如果我们愿意,完全可以把AspectJProxyFactory
当作ProxyFactory
来用!
2. 通过自动代理织入
针对@AspectJ
风格的AOP,SpringAOP专门提供了一个AutoProxyCreator
实现类进行自动代理,以免去过多编码和配置的工作,这个AutoProxyCreator
我们之前也提到过,即org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
。它是在AbstractAdvisorAutoProxyCreator
的基础上给出的一个扩展类,它的直接父类是AspectJAwareAdvisorAutoProxyCreator
。与使用其他AutoProxyCreator
一样,我们只需要在IoC容器的配置文件中注册一下AnnotationAwareAspectJAutoProxyCreator
就可以了,如下配置所示:
现在,AnnotationAwareAspectJAutoProxyCreator
会自动搜集IoC容器中注册的Aspect,并应用到Pointcut定义的各个目标对象上。如果我们通过容器取得现在的target对象的话,会发现它已经是被代理过的了,如下:
当然,如果把target作为依赖对象注入其他的bean定义,那么依赖的主体对象现在持有的也是被代理过的目标对象。
刚才AnnotationAwareAspectJAutoProxyCreator
注册到容器的方式是基于DTD的配置方式,在Spring1x以及2.x版本中都可以使用。如果我们能够使用Spring2.x版本,并且使用基于XSD的配置方式,还可以有另一种更加简洁的配置方式,如下方代码所示。
通过面向aop命名空间的<aop:aspectj-autoproxy>
,可以达到与基于DTD的配置方式中,直接声明AnnotationAwareAspectJAutoProxyCreator
相同的效果。
该元素背后的工作实际上就是由AnnotationAwareAspectJAutoProxyCreator
来做的。另外,不要忘了将aop命名空间的Schema定义引入XSD定义。
@AspectJ形式的Pointcut
暂时不做介绍,后面可能会补上
@AspectJ形式的Advice
@AspectJ
形式的Advice定义,实际上就是使用@Aspect
标注的Aspect定义类中的普通方法。只不过,这些方法需要针对不同的Advice类型使用对应的注解进行标注。
可以用于标注对应Advice定义方法的注解包括:
-
@Before。用于标注Before Advice定义所在的方法;
-
@AfterReturning。用于标注After Returning Advice定义所在的方法;
-
@AfterThrowing。用于标注After Throwing Advice定义所在的方法,也就是在SpringAOP中称为ThrowsAdvice的那种Advice类型;
-
@After。用于标注After(finally) Advice定义所在的方法,1.x版本的SpringAOP中没有对应这种类型的Advice接口定义或者实现;
-
@Around。用于标注AroundAdvice定义所在的方法,也就是常说的拦截器类型的Advice;
-
@DeclareParents。用于标注Introduction类型的Advice,但该注解对应标注对象的域(Field),而不是方法(Method)。
更多不做介绍,后面可能会补上