spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。, F* `5 S9 X) d$ h
那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现: . E2 O0 \: `' }7 v6 q2 @) U" J
? 切点(PointCut)
! t. C0 L. t& s8 P. H 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 / x# [) J2 d _# M8 g- Y5 U3 L
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
: n# j; d2 s9 l4 \' |/ z. a- _我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 9 k: F& L3 x$ a0 H% j5 R
<bean id="myPointcutAdvisor"
# C' X$ j' e& Lclass="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> / \$ Q. w( }6 P: S2 `* C
<property name="advice"> . e) g3 ~; w0 |* `; ?
<ref local="MyInterceptor" />
8 v7 B$ Y3 j; O: `6 f: o</property>
/ m* D3 n8 r! K3 B$ j% l" A<property name="patterns"> 7 m1 k2 [; k! O2 I7 ?5 }% \
<list>
1 N2 K: J7 B; n9 ~/ B4 o2 k. E& w1 |<value>.*save.*</value> 8 {; Y" e! `/ L! V5 ?2 Q2 M
<value>.*do.*</value> # f. D! N1 _9 s6 T% d# i: v
</list> " G1 @- m$ ]% |. X" G
</property>
% J! G- B4 b4 ]6 W</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
. n/ a3 ?) a; d U3 b. ` ? 处理方式(Advice) h$ ~4 @6 V9 \6 D4 ?
也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor: a+ S$ C4 S, `
package test.aop.spring; ' L: N$ r: _! f% j, J6 M* _$ t
import java.util.logging.Logger;
! X, J0 W1 s7 c6 L. [import org.aopalliance.intercept.MethodInterceptor; ( g- Q$ ~) z4 c" @
import org.aopalliance.intercept.MethodInvocation; /** / }+ `1 R' H1 _- g7 o! a
* @author xkf
2 x8 R+ I m$ w+ X5 H4 [. K**/
* T$ B+ w+ h: Q' `public class LockInterceptor implements MethodInterceptor {
: b: D- V. @" Q& C7 p+ q4 aprivate Logger logger = Logger.getLogger(this.getClass().getName()); " z, V6 ?1 T/ b" l A' E& j
public Object invoke(MethodInvocation invocation) throws Throwable { , |. E* e5 a5 v1 @" f+ S5 @
// TODO Auto-generated method stub
" O: Z: Z N" D( d, Q3 glock();
. s/ X) X7 s5 lObject ret= invocation.proceed();
9 r" L- L; j+ Q" q+ Zunlock();
$ `6 R3 b" [; Y3 z, y2 K, vreturn ret;
j( Z6 ~" D" }* f, A}
|* H, l; K3 \! G$ o/ pprivate void lock(){ 1 t* Q' U0 }4 K6 U- {2 o# V3 t1 [
logger.info("lock domain object..."); % A' T) B& X* r
}
~9 w; C+ _! dprivate void unlock(){
6 t% U" k* V- z1 S' g+ ulogger.info("unlock domain object...");
% Q$ J# H) x$ W0 g, ?2 U8 p5 f( Z}
% h" _" r1 x$ }/ m% C6 A}
) L ~% O# M+ b/ j# H 实现后,对应的Interceptor实现类在配置文件中的体现如下: + F. a+ L u; Y, Y6 M; F
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
: r3 z$ k6 L" t4 c& I) [" j 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。
! c) c2 v5 R' _- \: Z3 _) z6 K 对应的配置文件应如下配置从而实现这些内容: ' p+ q% f8 V L4 M, Z1 a {
<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">; V8 t) i' k. |) ~( `- E
<property name="proxyInterfaces">
2 d3 }. m5 u6 o2 Z<value>test.aop.spring.DomainObjDAO</value> 9 e' P6 K0 h+ g+ }
</property>
' r- _! D! K4 _<property name="target"> 7 G! Y3 b0 S- y' X" [; w/ Q
<ref local="impl" /> : A) i; |7 P' u; z$ a: C3 C# a. p
</property>
1 T5 Z0 T" ?8 W# N2 }1 R<property name="interceptorNames">
/ @& I. G! u+ I+ V1 s<value>myPointcutAdvisor</value> * Y( U, y: E1 d* T
</property> ' j: ?" ?1 D+ y2 Y, r) g
</bean>
& {0 m& L# v, C<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/> ! ], s2 J& z. Q$ |" g v
万事大吉!写一个TestCase来看一下运行结果: 8 r) J& h( Z/ S- \
package test.aop.spring; import junit.framework.TestCase;
( P5 K# t7 ~7 p* D+ himport org.springframework.context.ApplicationContext;
( j% k3 a0 a7 L2 [' x8 L& ?import org.springframework.context.support.FileSystemXmlApplicationContext; /** ( d f" f1 o9 E- c9 q+ e$ \4 K
* @author xkf , I& H5 V9 I: I# k8 s
*/ 8 o7 S9 q. I8 g7 F# Q: k; i" v
public class SpringTestCase extends TestCase {
% X: P. m. t' p0 bDomainObjDAO test=null; protected void setUp() throws Exception {
. Z1 C2 b. h# ]: k, k' x' k3 s2 rsuper.setUp();
+ S: ]* F! D$ Y! r4 Z% M" \ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml"); / l$ J% E$ @7 K3 L
test = (DomainObjDAO) ctx.getBean("myAOPProxy");
( }* f# I% n6 x2 Z} protected void tearDown() throws Exception {
" B7 a1 N# {7 A5 J( ysuper.tearDown();
% E/ ?9 |% S4 D: L3 l: k}
7 W# d6 L4 q' n: F/ W/ ypublic void testSave(){ ( N: I7 E/ x2 E
test.save(); / a, }1 q1 v6 F! F
}
( S/ Y7 L: M9 W+ O5 Z! T} * W0 G3 y* c% C
运行结果如下:
7 C; p, }* z2 w+ ~; ?0 H信息: Creating shared instance of singleton bean ''MyInterceptor''
x. J" v. x, _, t% X, \2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock 3 y6 V3 ~) x% a" ^, i7 q
信息: lock domain object... / S" [" E1 b4 b& V
saving domain object......
" _' l8 ^$ j7 o2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock 6 z5 }3 H( {7 B6 i' D. z* w: a
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。
; H: r7 x) j+ l$ t |