spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。
) r' ]3 ?3 |8 N& Y% e+ O那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
9 q- i: z( O1 H( [" @( B1 R4 ]? 切点(PointCut)
0 I1 Y0 k! t2 h' g3 F 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。
3 ]1 N, j' h& k7 G 对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
! d3 K4 W3 J6 J我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 3 K: N! J, U' S* N; l. c
<bean id="myPointcutAdvisor" * k5 R9 m+ E( S" P+ F
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 2 A z4 U) m2 p+ Q v1 i# }3 {
<property name="advice">
/ r, f/ W6 O8 }. m- ~6 n( Q' v<ref local="MyInterceptor" /> ; p) e4 h, W: P% M6 U7 t5 n. J
</property>
5 f/ r6 b" A+ ?* I2 z<property name="patterns"> 8 a; `4 f% L; ]
<list> {0 X$ ~5 M$ z; f& }: [
<value>.*save.*</value>
% Y" ~2 |6 n& O! _* f- B% f<value>.*do.*</value> , K! O/ r' }( ?6 k
</list>
9 B0 x" P/ x& y( R7 i( y9 k</property>
& L( W9 D V3 u' L7 R7 J( o</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
, U7 c' Z& d- y. r ? 处理方式(Advice)
# V' z* L6 d+ k 也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:. D1 Y, V1 M1 z* c( G7 A& @% d
package test.aop.spring; " D5 d/ }! C% d7 C1 f
import java.util.logging.Logger;
, o$ B9 F; r/ F5 ?) Qimport org.aopalliance.intercept.MethodInterceptor;
+ I( }* ?+ L) y' t) [9 e6 W' timport org.aopalliance.intercept.MethodInvocation; /**
" C1 U. C5 o Z$ w6 s* @author xkf ( ~/ ?' P( ^) t/ h& U8 X7 l
**/
$ w; u3 b, k' ` ^public class LockInterceptor implements MethodInterceptor { 2 S$ G1 A2 e8 @, T2 ^! g
private Logger logger = Logger.getLogger(this.getClass().getName()); 3 V" U5 i9 _7 ~, ?& M# r
public Object invoke(MethodInvocation invocation) throws Throwable { ( a3 g- g% j+ L4 _, }8 @
// TODO Auto-generated method stub 2 s5 d) ^2 y' I$ d9 A
lock(); 2 ~" o V; Q, B4 f. b4 D
Object ret= invocation.proceed();
, f& C6 u. P7 Runlock(); 7 N% s4 i% [8 ]+ v. I3 ^& C
return ret; + F7 v& H9 I' m! V
}
7 Q" ]+ G1 ]! C- G9 k4 M5 u# sprivate void lock(){
- E$ K6 j; M" N9 |8 v2 T! mlogger.info("lock domain object..."); 3 P, w% ]% I1 ]; r. r
} , |5 q! Y# n J# x! d9 `
private void unlock(){ - o; t, Q: b+ r! z0 `$ I$ \& F
logger.info("unlock domain object...");
2 e# a& k6 F2 p! p5 F$ ^} - f: M# ]9 O6 v, M+ y0 m2 _
} ; j |% y' D) t2 s1 R" J- Y
实现后,对应的Interceptor实现类在配置文件中的体现如下:
) z9 c% @. s3 O8 i1 a! z <bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/> , e: t+ i$ ~; _, G5 L% F
最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 p! }; t- {) y4 r0 _
对应的配置文件应如下配置从而实现这些内容:
, O+ {( ?$ D9 s3 L' R<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
0 s$ Q, E: \6 A' Q$ F( n<property name="proxyInterfaces"> 7 D0 }1 m* H6 w0 ]7 d
<value>test.aop.spring.DomainObjDAO</value> ! P5 e* z0 e9 s$ f
</property>
: p% q6 ^/ D* g% d<property name="target">
* c) [8 s4 ]9 V8 u<ref local="impl" /> 8 `1 ]4 j, X+ M% s# O9 f
</property> 7 L# K; p4 b! |! W5 y7 M$ D3 ~
<property name="interceptorNames">
; U) d" X. ~' j1 G: y/ {. o. u<value>myPointcutAdvisor</value> ) Y4 L( W2 s: d+ b- m" v
</property> 0 Q% ^- E3 m: K; e2 G5 M. l4 G& }
</bean>
5 }! e* _" a. L6 ]<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/>
5 Y$ f2 R8 y2 v( D, s万事大吉!写一个TestCase来看一下运行结果:
0 l% Z- O# K2 A1 i; bpackage test.aop.spring; import junit.framework.TestCase; 0 {1 k3 M8 x4 g+ l
import org.springframework.context.ApplicationContext; / N; q1 O- d s K3 f/ J3 b
import org.springframework.context.support.FileSystemXmlApplicationContext; /**
: L( E7 o C$ V0 N; A8 }' t* @author xkf
$ s1 O7 o, E1 V) Y; B3 g*/
n4 |1 }; q0 f* r9 spublic class SpringTestCase extends TestCase {
7 Q) q. x9 i% \, X% l( m6 vDomainObjDAO test=null; protected void setUp() throws Exception { : d' f) |, o' W* L q- O
super.setUp(); ! V p2 @3 z k5 p! L/ \3 X; @
ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
1 ~; I' Q1 [8 N1 s Btest = (DomainObjDAO) ctx.getBean("myAOPProxy");
0 P' y8 _! q, y& M3 Z5 Z( w) j} protected void tearDown() throws Exception { ' z: D7 j) f P9 ~7 b. s
super.tearDown();
& w* |* K4 ?" E2 o! p4 I}
0 Q+ o; ?3 o% h- x* j9 upublic void testSave(){
0 b4 _, O9 V: i; m' y, L+ O. utest.save(); 3 p. H Z/ A" y" }3 O* G2 |, W7 r
} 2 f8 S2 \/ H+ H5 _, l* D3 v
} ; o0 r* W7 v; Y W( l6 j2 z
运行结果如下:
5 v# c P2 m! y% X信息: Creating shared instance of singleton bean ''MyInterceptor''
8 p+ x+ @' K# k' d) S2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock
G! x8 @7 B, A+ C: g% C信息: lock domain object... 8 p# f |: |6 e' n' m3 p$ R# l
saving domain object...... 6 y) O$ N3 Z' w, u7 ^1 v% ~+ M, `" @
2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock
) `* C G8 l" \0 M8 g3 Q信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。 4 o, @: S3 I( E
|