spring aop
小结
总结前几天的项目实践,对spring aop的使用做个小结。
首先要理解的是AOP的概念
。
顾名思义,面向切面编程(
AOP
)是以识别和创建
切面
为基础
的编程。说它们是横切,是因为它们总是切入模块(如包、类和代码文件)的多个单位。
其次,要掌握spring aop的几个基本的概念。
切面(aspect):一个关注点的模块化,这个关注点可能会横切多个对象。
连接点(joinpoint):在程序的执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在 Spring AOP中,一个链接点总是代表一个方法的执行。
通知(advice):在切面的某个特定的链接点上执行的动作。通知有各种类型,其中包括“before”“after”“around”“throw”四种类型。
切入点(pointcut):匹配链接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的链接点上运行。
织入(weave):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。Spring在运行时完成织入。
在spring 2.0中声明切面、通知等有两种方式:一种是配置xml文件的方式,一种是基于@AspectJ方式的,即annotation方式的。但是这种注解方式只适用于Java 5的版本,如果是Java 5以下版本,只能使用传统的xml方式。
u
声明一个切面:
切面使用
来声明,支持bean通过ref属性来引用:
...
…
切面的支持bean(上列中的”aBean”)可以象其他Spring bean一样被容器管理配置以及依赖注入。
u
切入点声明:
切入点可以在切面里面声明,这种情况下切入点只在切面内部可见。切入点可以直接在
下定义,这样就可以使多个切面和通知容器共享该切入点。
在这里expression表达式是一个正则表达式,它的一般的规则为:
execution(modifiers-pattern ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
其中带问号的modifiers-pattern?(public/protected) 和 declaring-type-pattern? throws-pattern??可以不填
可见execution(* *..BookManager.save(..))
* 第一颗* 代表ret-type-pattern 返回值可任意,
* *..BookManager 代表任意Pacakge里的BookManager类。
如果写成com.xyz.service.* 则代表com.xyz.service下的任意类
com.xyz.service..* com.xyz.service则代表com.xyz.service及其子package下的任意类
* save代表save方法,也可以写save* 代表saveBook()等方法
* (..) 匹配0个参数或者多个参数的,任意类型
(x,..) 第一个参数的类型必须是X?
(x,,,s,..) 匹配至少4个参数,第一个参数必须是x类型,第二个和第三个参数可以任意,第四个必须是s类型。
u
通知类型
(advice)
:
有四种通知类型:
Around 通知、前置通知、异常通知、后置通知。这几种通知分别继承与这几种接口:
MethodInterceptor、 MethorBeforeAdvice 、ThrowsAdvice 、AfterReturningAdvice
前置通知(before advice):
Before 通知在匹配方法执行前进入。定义一个前置通知必须继承MethodBeforeAdvice接口,实现before方法。前置通知可以在连接点执行之前插入自定义行为,但是不能修改链接点的返回值。
After returning通知在匹配的方法完全执行后运行。它必须实现AfterReturningAdvice接口,并实现afterReturning方法。一个后置通知可以访问返回值,但是不能进行修改。被调用方法、方法参数以及目标对象。
After throwing通知在匹配方法抛出异常退出时执行。
Around通知在匹配方法运行期的“周围”执行。它有机会在目标方法的前面和后面执行,并决定什么时候运行,怎么运行,甚至是否运行。使用around通知必须实现MethodInterceptor接口,并实现其中的invoke(MethodInvocation invoction)方法。Invoction参数暴露了被调用的方法、目标链接点、AOP代理以及传递给方法的参数。Invoke()方法应该返回调用结果。
u
增强器
(advisors)
“advisors”这个概念来自Spring 1.2对AOP的支持,在AspectJ中是没有等价的概念。Advisor就像一个小的自包含切面,这个切面只有一个通知。切面自身通过一个bean表示,并且必须实现一个通知接口。
Spring 2.0通过
元素来支持advisor概念。格式如下:
expression=”execution(* com.xyz.myapp.service.*.*(..))”/>
advice-ref="advice"/>
同时,我们还可以使用pointcut属性来定义一个内联的切入点表达式。
所以可以写成如下:
expression=”execution(* com.xyz.myapp.service.*.*(..))”
advice-ref="advice"/>
下面有一个实例,这是我在项目中的运用:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-autowire="byName">
advice-ref="insertAdvice"/>
public
class
AfterInsertRvertAdvice
implements
AfterReturningAdvice{
private
StaticPageService
staticPageService
;
private
LocalCache
localCache
;
public
void
setStaticPageService(StaticPageService staticPageService) {
this
.
staticPageService
= staticPageService;
}
public
void
setLocalCache(LocalCache localCache) {
this
.
localCache
= localCache;
}
public
void
afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3)
throws
Throwable {
if
(arg0.toString().equals(
"success"
)) {
System.
out
.println(
"AOP after advice: attribute is "
+ PropertyUtils.getProperty(arg3,
"model"
));
System.
out
.println(
"AOP after advice: attribute is "
+ PropertyUtils.getProperty(PropertyUtils.getProperty(arg3,
"model"
),
"noteId"
));
//localCache.remove(arg0, arg1)
String id = (String) PropertyUtils.getProperty(
PropertyUtils.getProperty(arg3,
"model"
),
"noteId"
);
staticPageService
.updateFlagById(id);
}
}
Spring 的代理缺省使用j2se的动态代理来作为AOP的代理。这样任何接口都可以被代理。同时Spring也支持使用CGLIB代理。对于需要代理类而不是代理接口的时候CGLIB代理是很必要的。
使用spring2.0 和spring 1.*的最大的区别,就是xml文件标签的语法配置。Spring2.0开发组建议使用xml的schema方式,如上例所示:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-autowire="byName">
但是Spring 2.0中冶提供了基于DTD的设置方式:
建议使用第一种,因为有时候会出现无法加载文件的问题。