spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。
+ X( z6 l3 w" e0 B# r/ r那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
, T% z, s+ A/ q, Z5 D? 切点(PointCut)
4 ?; H1 R1 g! @" o 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 6 I" w: u9 Y& i- Z6 [
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。% H. h ~& f5 P
我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 % Y; a6 G* r8 e3 d, C" j% f4 b
<bean id="myPointcutAdvisor" - X. C* I' x+ X6 j* }
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 4 i( @ R0 ]% r6 r4 z, Z
<property name="advice">
$ ^" j. C% G7 q; J. J<ref local="MyInterceptor" /> % |8 n) |% G/ {9 j6 [ H
</property>
2 k$ A, H1 z T. I U4 w<property name="patterns">
, f2 }/ E3 ]# g; r. p; f<list>
5 k1 _# S+ r! x<value>.*save.*</value>
. A3 N: X7 C |$ i0 n1 Q* N: B. s% r<value>.*do.*</value> ! k' v# O$ k& l$ G; c3 b4 Z
</list>
. N5 }3 o# r5 g' w</property> : I; {8 Q) w5 z1 T2 v9 ?4 ~
</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。 % N0 T! Y* B0 p: ~
? 处理方式(Advice) / r) d3 i' U2 m% a
也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:
6 e; R- O% |9 @/ [) X! z+ [/ S spackage test.aop.spring;
8 Y' W+ g% v0 D8 v) ^; Uimport java.util.logging.Logger; / X4 K) E4 z' d# R" P) h
import org.aopalliance.intercept.MethodInterceptor; , k2 B g* Y; K2 o
import org.aopalliance.intercept.MethodInvocation; /** % w, {3 R2 ?% R! }5 a2 G
* @author xkf
5 ~# e9 }7 p3 ~ T6 o5 k0 ]: h5 w: B- N**/
% E- @! i7 r$ C1 U @public class LockInterceptor implements MethodInterceptor { , q( O4 y2 B+ Z0 y# ?* b% t1 E
private Logger logger = Logger.getLogger(this.getClass().getName());
4 V2 y0 J) Y- |6 u' i5 Rpublic Object invoke(MethodInvocation invocation) throws Throwable {
+ e) `# F0 e3 }. K+ }// TODO Auto-generated method stub ' o9 o4 O; A( t: H5 F
lock();
# R' j4 X" g) b g: LObject ret= invocation.proceed(); {7 ~& ?1 R* w8 B! `' ]4 B) k5 d
unlock();
8 {1 J6 ~- D+ ?$ ureturn ret; 3 D8 e$ N* l& ^3 S/ p- N$ @
} ( G3 Z( G4 d2 p2 q0 l
private void lock(){
3 P0 \7 M, g0 A; Y" K; }2 Glogger.info("lock domain object...");
6 \5 H, U( y" P) ]}
+ u: v- o, n8 [" |9 C& G! cprivate void unlock(){
+ u* K. N0 `8 d! p4 Elogger.info("unlock domain object...");
$ t' t+ M" W; }}
- h6 A9 D7 _$ R, Q0 p" R}
6 z- X" A; ^: n/ X6 U) U 实现后,对应的Interceptor实现类在配置文件中的体现如下: : e7 V b3 x) p- Z( q( l' Y
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
3 [+ \0 c: Y0 R, ?2 w 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 ; e0 U9 w; x( O/ d
对应的配置文件应如下配置从而实现这些内容:
+ e9 d; g2 }' x) g: K5 h<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- H7 o9 n. T6 t9 T% i3 c! J% }- n; I* _<property name="proxyInterfaces">
% t. l# d; g5 b% v& t6 U* Q, r<value>test.aop.spring.DomainObjDAO</value>
8 E' y @: l; c& Y5 {% d</property>
" k) Y$ b; M+ r% ^* m<property name="target"> & U1 w. B3 V: E
<ref local="impl" />
0 x, g% v. [! s</property> 8 I- J' D4 W. h
<property name="interceptorNames">
8 {- u% G2 n2 V9 q1 e- H6 w<value>myPointcutAdvisor</value>
% `- ]* i3 v# a. t: v</property>
( ~4 j3 V6 S( ?* C4 p9 J2 _</bean> 5 ?. j9 x8 {3 k. S- }& Z
<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/>
: t4 S9 W' V# x! S% ^+ ?" _3 G万事大吉!写一个TestCase来看一下运行结果: ' J# h1 K5 k# h \1 u* B
package test.aop.spring; import junit.framework.TestCase; . G/ D' m8 \6 k$ ]& m( ] v8 J6 q
import org.springframework.context.ApplicationContext; 0 O, s3 q. ]# t" o6 o# d3 c9 R1 b
import org.springframework.context.support.FileSystemXmlApplicationContext; /** + }7 k' U" h V4 `5 K
* @author xkf 2 x9 r+ C, s9 |" Q3 U
*/ 9 i5 x- }6 k) L' b5 ^
public class SpringTestCase extends TestCase { ( G% a! }/ t. H5 a4 U9 g
DomainObjDAO test=null; protected void setUp() throws Exception { ) I8 N' X) X5 s: b+ d% A( B
super.setUp();
9 g9 C" I% o `5 `& o. yApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
3 v. Y6 g5 }8 P" C; C# {( btest = (DomainObjDAO) ctx.getBean("myAOPProxy");
+ w1 w4 G+ }0 M+ m3 S4 K0 a} protected void tearDown() throws Exception {
0 s. f$ ~1 R/ X( R6 R0 K+ G K1 `super.tearDown(); / Y' R& \, k3 O. k/ f. ?
}
$ ]- {4 b+ Y9 [/ K: ?public void testSave(){ ; W5 n- b1 r" k9 @
test.save(); 5 L4 b1 s. ~6 p# b4 p
} ! O* L# [! O( V
}
$ F3 R4 y; W: W; y' f运行结果如下:
$ f5 [ }/ G3 K: s3 g4 f3 \' d信息: Creating shared instance of singleton bean ''MyInterceptor''
0 v" |' D6 M% o/ ^2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock / Y) Y5 @- J4 h
信息: lock domain object...
- U: k% X' P! L% }4 h) D# ]saving domain object...... & v d: |2 ~0 N! k: L/ d
2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock . i% t6 I/ e: f$ n, Z( p
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。
& L I1 M2 P/ J; E |