spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。
' D5 D; |( G7 R0 G0 o( t1 ] U* j那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现: $ z0 a) P+ ?3 {9 w) e u
? 切点(PointCut)
8 o0 a+ ~. R, N/ r7 D 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。
4 d2 R9 a. P' K: t4 m5 K/ E% h 对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
3 V/ |6 {: b7 b0 s6 f2 _$ V我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 ; u2 l9 ]- X/ ?
<bean id="myPointcutAdvisor"
% s7 `4 V% V% ?. g5 V! k5 V$ w8 G9 Pclass="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
3 k, R! t) K( J g<property name="advice">
4 I& q' P) h! V2 B- |" n9 H<ref local="MyInterceptor" /> / q4 H& z4 \( A, o
</property>
5 Y' w6 E0 l$ G5 W8 \+ c- Z2 m<property name="patterns"> 8 |2 C3 M0 J5 r; m. v3 M
<list>
3 O5 X$ P+ g) S5 Y ]8 V<value>.*save.*</value>
) L6 L! b" t1 H3 u% U<value>.*do.*</value>
" }5 L" A+ d" y; G1 E8 D( q</list>
9 b$ \4 U% k/ v1 {6 A) ~. I</property>
2 \4 F# K8 o8 g1 `! J5 X8 A</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
7 F! ~- K. m s: M ? 处理方式(Advice)
7 f; W& p% B& e' i 也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:
2 j; M+ ]0 X0 s8 H& }. y& gpackage test.aop.spring;
( F' p+ K# Y; q( fimport java.util.logging.Logger; 7 V) V" c1 u8 I5 Z7 E; h ^1 \
import org.aopalliance.intercept.MethodInterceptor;
6 R8 Z2 J% V$ U4 t; _import org.aopalliance.intercept.MethodInvocation; /**
6 X( m# F( k* W6 I: I" J* @author xkf
8 h, N% O& k( I6 D0 ~5 r# R9 p7 W**/
+ c J( n6 ^: X& p& U! B0 G9 ]. \) Npublic class LockInterceptor implements MethodInterceptor {
P( F* u! S: `' O8 T( gprivate Logger logger = Logger.getLogger(this.getClass().getName());
& Q/ Z p! o8 i+ T7 G3 Epublic Object invoke(MethodInvocation invocation) throws Throwable {
! t: ^0 C* V p5 @. P// TODO Auto-generated method stub
! Y$ j( D0 n/ v( B* h _& p: [$ _lock();
8 \6 s6 r6 }: ^8 q& cObject ret= invocation.proceed(); & c4 e, k* H' F" i7 u7 v9 R
unlock();
+ j( ~2 a! Z/ ]) H$ Preturn ret;
( W. w; p; k' H* {5 e: R, O. ?} . c6 l4 v6 j" Q; I1 l* ]
private void lock(){
8 F' O: E0 ]; Q. Ilogger.info("lock domain object...");
# a- k6 ]: Z: c6 {8 V8 `; Q& R. i! m}
6 D% u, u! |7 a! p( pprivate void unlock(){ , T [$ u" _$ n- ]& Y
logger.info("unlock domain object..."); ( Z) v. ^! H0 |& ?9 ~& ^
} $ l( Y( u3 |; ~/ O* O9 m
} 6 S4 x0 K9 ~& r4 {4 G
实现后,对应的Interceptor实现类在配置文件中的体现如下: $ U. Z) A2 f3 O5 _
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/> 8 ~- i: l5 i) X' q% }1 u
最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 1 k2 j2 R* w7 k' r
对应的配置文件应如下配置从而实现这些内容:
) t8 Y& R: |: b9 v<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
$ N! _) U I s3 Y0 {<property name="proxyInterfaces"> 1 |, Q2 S# Y1 q3 v& B
<value>test.aop.spring.DomainObjDAO</value> , F( Q Q) O: W& Z. E' J$ k, ~. Z ?
</property>
6 R, c- C6 a3 [, B/ B. Y<property name="target">
( G, r8 l/ N8 L' j2 f1 m<ref local="impl" />
* Z' Y9 A) V. x) Q- ^</property>
3 O$ R5 I2 m: A: b- G7 U<property name="interceptorNames"> & W" [4 I) {$ Z3 B9 n6 v
<value>myPointcutAdvisor</value>
% e0 h) i3 g9 M4 Y P1 v& ] R+ ^</property>
- k. Y2 @: O5 |! T2 U/ e</bean>
3 [: l5 }+ a5 Z1 U5 L, Y<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/> 5 M4 y! ^& h5 F, M
万事大吉!写一个TestCase来看一下运行结果: 4 _/ W4 O6 F" Z* o! L5 D1 _
package test.aop.spring; import junit.framework.TestCase;
2 g) y' F. g+ c1 O6 u9 Eimport org.springframework.context.ApplicationContext;
" U5 ?5 L) l Q, h1 Q; ^import org.springframework.context.support.FileSystemXmlApplicationContext; /**
7 B$ S& O0 o" C! n, c m6 L* @author xkf
3 c4 _6 Z& w5 v3 H6 h3 P*/
0 T6 k/ P' | [! i% h. z1 jpublic class SpringTestCase extends TestCase {
# G: ^2 V7 @5 x" O/ oDomainObjDAO test=null; protected void setUp() throws Exception {
8 [# L/ X( D p, q# Psuper.setUp();
# I, p) E; v' S8 ]" X" S, uApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
% Q6 k' m# _! L$ \* [# x$ p) dtest = (DomainObjDAO) ctx.getBean("myAOPProxy"); ( X& e4 B# h3 Y0 a
} protected void tearDown() throws Exception { 8 j0 v- ~4 Q; B! v: h( k" H C
super.tearDown(); . E5 U: u. N5 {
}
3 T+ z! t/ N9 z. d* z8 l8 S; J! Gpublic void testSave(){
4 c g2 s+ m& G5 T* `/ ~test.save(); # V" @. d8 {' @9 ^# E5 Q
}
* W# n& }3 H9 p3 W} ) t, t- O0 i9 j5 N
运行结果如下: ( M' Z& c; P O2 B L4 @
信息: Creating shared instance of singleton bean ''MyInterceptor'' * @7 |5 V1 V& s4 H
2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock
- @, M6 F/ w1 J) ?信息: lock domain object...
9 a1 c: R$ B, t9 x' Tsaving domain object......
1 G- e S/ Y$ {/ g/ P6 K2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock
; A4 K: ?4 \ _/ j* l8 A+ O, z信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。 . x, x1 r y* r9 W# L% o0 J5 [
|