spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。& k" p# ^0 i m+ t7 l& q
那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
& j5 |2 k# T9 I+ h' S? 切点(PointCut)
% v# C) o3 ]/ B- V( N1 U4 Q 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 # q4 u" |$ o W4 }$ h$ Z: N4 K
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
5 @) D9 M4 z) q3 X我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 ; E$ k6 L1 l& @6 P- j' s: ^
<bean id="myPointcutAdvisor" 0 ~0 x" E! |: C# A" J7 Y1 T. t' E
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 6 W* G9 r6 F S# m1 ]* J6 o. X2 b
<property name="advice">
3 p. W5 u. m! G$ Z+ u<ref local="MyInterceptor" />
4 ~/ l+ d8 N8 a& @# I</property> , c' m( J. o* e! `
<property name="patterns"> 1 k# W6 a) H+ B, }. ?, G
<list> $ q# q# |0 S: x5 E; i
<value>.*save.*</value> 4 B7 x1 z6 _1 @
<value>.*do.*</value> 9 g2 n: v* Y' s: s" L# h" U
</list> " Z2 M$ K& S$ {0 d
</property>
5 ]! i6 ~1 f1 E9 m+ X</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。 ) K2 a7 g; n( q
? 处理方式(Advice)
2 u) T1 h0 ]3 N( j 也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:
1 d5 j' C5 {: j; Jpackage test.aop.spring; ( n8 C) i3 W3 E( H
import java.util.logging.Logger;
4 N" y3 Q4 x8 U% eimport org.aopalliance.intercept.MethodInterceptor;
; G" W W- ?+ l, }import org.aopalliance.intercept.MethodInvocation; /**
; h; R0 l, Y, |! G* @author xkf 2 a$ _0 v' C0 D0 I( x, E
**/
! W: ~) k" \: R& u" |' jpublic class LockInterceptor implements MethodInterceptor {
( I& h; r/ Y$ ^private Logger logger = Logger.getLogger(this.getClass().getName());
% I. d$ [ Y9 E* x( b, T( Dpublic Object invoke(MethodInvocation invocation) throws Throwable { 2 T, j- D: m) s* i9 G4 l
// TODO Auto-generated method stub
+ C9 w" ]: o! F3 `0 tlock();
- I; P8 _" t' P3 vObject ret= invocation.proceed();
$ ]9 [0 _$ P, y& [! }: O8 Q* M9 Punlock();
) w. r. y( G' X& ~return ret; + B8 U- b+ u- U9 y" R, G2 T0 h
}
9 P' Y* R& c4 i) c4 vprivate void lock(){ + K# g! B9 s, V2 S
logger.info("lock domain object...");
1 f( Y5 C$ j; W h. F; a2 f}
; @, _) W% r0 Y5 e% I+ G6 xprivate void unlock(){ ' W3 S }! \( y- K( h1 X
logger.info("unlock domain object..."); ( p/ I8 d! G' J0 p7 g% L6 ]' J
} , ~ K6 E. E3 N/ n
} + O- [/ z+ C% Z) @: U" c3 e
实现后,对应的Interceptor实现类在配置文件中的体现如下:
! _9 p. c6 [* P$ \4 o" q; i* h <bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
' T+ G* ?, |' _ }& t3 d 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 ( P- e5 ?) h( V w9 [$ I' c
对应的配置文件应如下配置从而实现这些内容:
0 g3 s( C7 l/ V& t, d<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">1 |; J9 w# q$ _3 ]( I
<property name="proxyInterfaces">
& z2 v. J: @) q0 H" d<value>test.aop.spring.DomainObjDAO</value> $ x# w/ T9 H- a5 x
</property> # C/ w5 g5 T7 a8 t( X' V
<property name="target">
' C# D% d9 d8 t' V' V5 S q8 I<ref local="impl" /> 9 c0 y+ H0 F+ C, {# e! @( V: y$ D
</property>
- k8 }# [3 ?: a- \$ a<property name="interceptorNames"> u* a: H* a4 F5 I
<value>myPointcutAdvisor</value>
; P1 }' v7 k0 p5 q) q</property>
9 [ W! K! _9 n C8 _! Z) G) Y</bean> 9 v% ^3 n2 P8 u: h( {* @% R5 a
<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/> 5 R) p3 ^) D! x$ [% w
万事大吉!写一个TestCase来看一下运行结果:
" @% |7 N. W! ^+ kpackage test.aop.spring; import junit.framework.TestCase;
0 X8 O/ o) _; Nimport org.springframework.context.ApplicationContext;
% f# d( t* I ^6 \ K2 oimport org.springframework.context.support.FileSystemXmlApplicationContext; /** . \2 w; M! V2 ]$ Q
* @author xkf . Z3 Z# K4 ?5 z- K
*/
! B1 U6 C6 }. k5 fpublic class SpringTestCase extends TestCase {
. f# L4 ?; f1 K) q/ R0 Q8 ^DomainObjDAO test=null; protected void setUp() throws Exception { $ F+ z) o$ H6 o# q1 l/ |
super.setUp();
; R0 N4 [$ T" O0 ?9 a& Z8 KApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
* a* O; W( G, ]" y. Ctest = (DomainObjDAO) ctx.getBean("myAOPProxy");
% `, h. T/ F. y1 Q# Y} protected void tearDown() throws Exception { ! a! Y# [8 O2 q( g- J: ]9 J( w
super.tearDown(); - V* H" e6 H% F: c( H$ X
}
5 w% V/ m" q# \$ W1 Q1 F/ q6 Hpublic void testSave(){
5 N: O& R+ `6 \1 V1 ]. ~2 E) w9 ttest.save();
, M9 m3 @( p5 E4 e- @6 H1 ?( I}
9 L" u7 V$ \1 u5 @ j2 M) x} + T$ i% ?8 |1 R* p# D& z
运行结果如下: 5 O2 D5 e1 B) ^2 }2 N
信息: Creating shared instance of singleton bean ''MyInterceptor''
2 B: M; ?. q$ M$ i2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock 8 K% ?$ S5 O0 Q2 s0 p: W* l
信息: lock domain object...
) X" f3 l* n0 v3 N' ssaving domain object...... ; u$ y( o) f8 |/ ~) k/ S" q$ h, P5 K
2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock % l6 A) I2 K4 o# m' l' f! X6 A
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。 ' Z6 ]3 c6 ~; v. F0 M; ]: X
|