spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。" u8 _5 R! `+ ?& n
那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现: ( Z/ ]9 m/ U" Y2 z( ~( ?8 ?0 ^
? 切点(PointCut) s m/ w1 J. i6 D8 B5 s; _/ f
一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 ; w. y& z, p) i7 y( r0 f
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
! I8 f- E/ Z* ]2 D" m2 `- a我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。
# d: [2 H% D- o<bean id="myPointcutAdvisor"
- w3 ~: S2 _% {! e, @, [( e3 m8 F4 o1 Aclass="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 7 S* e5 W- X! f5 A6 B7 K, L
<property name="advice">
+ g O+ M* I) Q# C3 O9 ^6 H3 [<ref local="MyInterceptor" />
( [4 o4 z- T3 T: S- j* T: M: a, f</property>
5 J0 W$ }: d0 m7 M# i& J7 C<property name="patterns"> / u3 g; A' j' s! \; N( m* N) Q' a3 N
<list> 9 e1 l2 G4 K/ w. |5 C# X
<value>.*save.*</value>
& @; I p+ u* O<value>.*do.*</value>
+ Z4 S/ v, s+ Q* |% C& O4 t2 @</list>
+ U3 }' m4 i* r0 [0 ]* v</property>
+ |$ E+ B. K, J. `1 ^# j: U t</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
9 P! i9 J2 O( f1 N v; R( ^% H ? 处理方式(Advice) : K1 s( ?* Q6 B/ H2 _; b3 O7 M6 E
也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:) \' e" `* W ]+ ~0 s$ ~
package test.aop.spring;
/ V; N5 V/ s" t, L5 y; s3 O1 dimport java.util.logging.Logger;
) p3 }$ N' H" j& W. j; k( gimport org.aopalliance.intercept.MethodInterceptor; 9 r- {1 B% |4 s: V8 \% l9 G
import org.aopalliance.intercept.MethodInvocation; /**
0 O8 e% m/ i8 r7 E: g* @author xkf
! `7 ]+ `6 J7 @) F**/ % T; K: r8 C) F C1 M
public class LockInterceptor implements MethodInterceptor { 6 B$ h8 n' k; j" m
private Logger logger = Logger.getLogger(this.getClass().getName());
* k9 q7 G. W( e5 x6 ^3 |public Object invoke(MethodInvocation invocation) throws Throwable { ; x& J3 F0 W; |5 T# `( m
// TODO Auto-generated method stub
8 @2 v/ m- B* C8 i+ _3 i/ e" jlock();
- U: W; E) m) R0 rObject ret= invocation.proceed(); ) q5 W: F. v, B: S
unlock();
x8 F+ m$ Q" V/ Zreturn ret;
$ R# T; e8 R: @( r# h. X$ {}
9 h1 K# Q+ A6 U0 M# p4 v$ Y* T9 Sprivate void lock(){
|' B. S4 w7 a% }) tlogger.info("lock domain object...");
; e0 D- F% j$ a( F: o} ( H( w, T* G( t4 ]( w
private void unlock(){ $ }/ B; E# g1 m4 K! E1 \/ @1 ?% b
logger.info("unlock domain object..."); . H4 b* x+ A1 m9 y- H( e- p
}
" f: k3 u. Q5 i% Z: K, l) d* J} ! T7 B4 ~0 B: Y4 U1 h: J8 F ]# U
实现后,对应的Interceptor实现类在配置文件中的体现如下:
2 a5 D( Q0 ^6 S8 l6 x2 U4 n <bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
, v* Y' N* m/ i: S7 a6 v! e 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 4 S, w2 c3 X% u9 a
对应的配置文件应如下配置从而实现这些内容:
0 h/ t0 W8 K: H2 M4 ]: P( `<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> ]0 [5 `0 y: I- u% y
<property name="proxyInterfaces">
- Z8 D4 L1 Y+ z) X1 t<value>test.aop.spring.DomainObjDAO</value> ) ~! h& [0 p2 y2 f6 m: Y' w
</property> : x: t+ y) I+ J: X/ S* e1 {
<property name="target"> * h( Y) p% b& F
<ref local="impl" /> - |, h. y! {3 B0 T( k" R4 \7 }
</property> : Q# W3 u! s8 x3 ^% {: ]
<property name="interceptorNames">
9 D' h& `' [4 ]; s( p<value>myPointcutAdvisor</value> 1 k& Y" G) Z! D/ b7 w
</property> 4 ^; l* l* J/ t% R0 f: ?
</bean>
: V2 j5 i8 d* I1 q* Y<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/>
$ i8 Q# v+ L( o4 v万事大吉!写一个TestCase来看一下运行结果:
! E3 r- w0 [+ G6 c) R6 Tpackage test.aop.spring; import junit.framework.TestCase;
0 t% v2 e) R7 s- p/ e' dimport org.springframework.context.ApplicationContext;
7 o) `* q6 j( l0 r: [( t: \* }import org.springframework.context.support.FileSystemXmlApplicationContext; /**
4 [' F2 Q% }! |5 j6 _" x, Q* @author xkf % i5 E3 h1 q& e+ F
*/
0 m, Y' F- f, [8 ?, Lpublic class SpringTestCase extends TestCase { 5 H7 j6 l- q! \& \, ]) Z
DomainObjDAO test=null; protected void setUp() throws Exception { ' Q$ u+ K$ j+ r+ _$ P3 O
super.setUp(); 6 \% \ L0 J0 g% H; d+ \* E' s1 E
ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
: v u) a V& A9 }- ^test = (DomainObjDAO) ctx.getBean("myAOPProxy");
" ]$ X1 ]: P1 Y4 p8 B} protected void tearDown() throws Exception { : [/ H0 s! U$ q' w! o( e$ ?
super.tearDown(); 3 M) I; t5 d; q2 ?0 e
} # k; u* F2 y/ p/ d, P
public void testSave(){ 6 T$ l2 ~! p, l. e3 |7 h' j! c. }6 v
test.save(); 7 L. k0 f9 g/ E, m1 s$ L
} . C# e) [# X- S2 {9 |9 z R F
} 6 e/ @, ?& a% S0 P7 \2 h
运行结果如下: ; w8 z+ \. e' `- M
信息: Creating shared instance of singleton bean ''MyInterceptor''
( i4 P/ @! [0 p6 w/ q) u" k2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock
+ Z- M8 [# @- R c) g4 R信息: lock domain object... 5 {' Q$ t8 Y( M
saving domain object......
+ c+ W4 E( [$ v2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock & |$ ~. ^" C& T
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。
0 t, ^1 U D4 g0 _2 | |