spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。
0 [2 B# P! ~0 D- Y那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
/ t2 C- t: [: ?" N" ?? 切点(PointCut)
" Z; [; C2 \* b5 @ 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 8 a( w v: W9 e
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
) _' ^2 w3 E; I& m) J9 k2 h我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。
8 n O1 f( y; H9 S<bean id="myPointcutAdvisor"
- f6 M/ N: {5 \) p" Q- Mclass="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
s: ] p+ {: r" ^<property name="advice">
, |$ `6 `: y& ^+ o) X! J! Z9 b<ref local="MyInterceptor" />
# c$ \7 j& K6 ]% K/ e' h- f</property> 6 n2 x# l( i1 L$ `4 p( K
<property name="patterns">
0 |) W" u$ Q) I<list>
0 ?0 i8 d, Z7 e: J1 } N<value>.*save.*</value>
1 T( t# t. z4 s* b" T4 J u% x<value>.*do.*</value> / b& T* u- r3 }7 M# S' T1 @" O
</list>
# ~( }2 o$ z, y" u2 l</property> $ Q: |8 K& J( |0 v+ \
</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
/ ^3 N' F0 Z( M. b4 b6 W8 n+ I ? 处理方式(Advice)
, H0 B/ u- `& J 也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:' D. }2 A7 `# b# a1 V2 O1 d" [
package test.aop.spring; . { _2 q( I; v8 q
import java.util.logging.Logger;
% p6 s2 e+ @/ p+ }; himport org.aopalliance.intercept.MethodInterceptor; & L7 [) X/ Z, \; I3 K
import org.aopalliance.intercept.MethodInvocation; /**
% K6 d, I J/ X4 c* @author xkf 8 m4 a8 B1 Z: y4 v: \( `* F7 n* z* |
**/ 4 c" q5 v3 x% h5 Z
public class LockInterceptor implements MethodInterceptor {
$ R/ T& |2 D1 J0 }- v1 Uprivate Logger logger = Logger.getLogger(this.getClass().getName());
, P7 g& H6 F" u: ^' \- {2 kpublic Object invoke(MethodInvocation invocation) throws Throwable { % S5 ~- V3 a) |4 E: S) v! h$ i/ n) O3 O
// TODO Auto-generated method stub
( |% x( k! z- l- }+ Q1 @lock();
/ f, s2 A# d5 h- h4 Y XObject ret= invocation.proceed(); - U q3 b7 u* I @
unlock(); ' ~! @; U( Y4 U3 S) p1 T
return ret;
: f/ L' j; a7 a& s}
2 B4 `+ V3 Z; C3 rprivate void lock(){
2 ^8 J; C, ^5 m, \9 flogger.info("lock domain object..."); : U0 N: b4 V% ~0 q* W$ b
}
0 U+ { d. O/ }; G: t* Uprivate void unlock(){
2 Q$ r$ i' w. M0 Qlogger.info("unlock domain object...");
; I9 l" t5 ?. e, t" X! }* {; M9 z} 4 ?( F9 b, l3 V( r5 B
} + n$ ]% K- }2 j
实现后,对应的Interceptor实现类在配置文件中的体现如下: * u: D& L5 b R4 ~5 G6 I, O
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
& E# ~8 C0 }1 J0 D! t 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 ' h2 A* ~5 R& X$ f. G ^9 C
对应的配置文件应如下配置从而实现这些内容:
/ G: Y3 e2 p: p7 w( t# ] }<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
0 b, Q; B& _7 ` v' |% Z$ J<property name="proxyInterfaces"> ( t# O# i [9 ^3 N
<value>test.aop.spring.DomainObjDAO</value> " q5 U4 _) W' Q# A
</property>
( z" w9 F' ^4 E5 n4 A<property name="target">
2 [3 E" g0 c# v/ r<ref local="impl" />
+ X+ D/ r8 l1 R* D0 l</property>
1 O" g' [$ ^3 l: b8 M* s<property name="interceptorNames">
1 A0 k7 c+ v# ^+ m _( d<value>myPointcutAdvisor</value>
: h+ E7 s+ e. L _% _" o; p' W9 `+ j</property> 9 A2 E" W( ]" x6 _2 A: n" J
</bean> % g+ J# j) o) U; R
<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/>
* U4 ^' c* Z! Q万事大吉!写一个TestCase来看一下运行结果:
6 f$ t/ e8 |( Ypackage test.aop.spring; import junit.framework.TestCase; $ I2 r/ X+ `4 ~- W! x) y
import org.springframework.context.ApplicationContext;
4 ] ]) J4 M' {( F1 \# X& eimport org.springframework.context.support.FileSystemXmlApplicationContext; /**
3 H& e; i; n* @! Q1 z* @author xkf
. h& r Y9 t' j0 X+ S: z*/
% a7 M5 X! L3 r: B* s0 w6 x. wpublic class SpringTestCase extends TestCase { ( X7 z7 d5 P: [1 r7 b( n
DomainObjDAO test=null; protected void setUp() throws Exception {
# E% p) O1 J1 B0 rsuper.setUp(); - y% K+ j! \1 E, p
ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
8 n4 V$ P; F0 o$ t' Y6 X$ ptest = (DomainObjDAO) ctx.getBean("myAOPProxy"); % u' W+ x; v6 \0 E
} protected void tearDown() throws Exception { ! t$ O W# {1 p. I
super.tearDown(); . j+ Q2 q) G- D
} 3 ^- m- X- z' e8 q7 o' S$ d( T
public void testSave(){ 4 b G3 w5 _9 t
test.save();
, F- p$ h! a; N2 d% k+ N- A q} ! ]- [: Z4 Y N# Y: B
} . X' ?* ]/ |* S& k$ }5 T9 W
运行结果如下:
: U5 A- ~) C8 k: J信息: Creating shared instance of singleton bean ''MyInterceptor'' 2 d) R1 Q/ F# h: |# e: T' t1 Z
2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock ) L' ]: U9 y1 m6 W* w A
信息: lock domain object...
5 S2 s# J. t/ H, ]3 A& N6 Bsaving domain object...... & L- Q; ~+ ]3 t t1 W7 Q0 d7 ?% E% n
2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock 2 o ?# P7 e$ a% A) {' j/ W3 l7 v
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。 ) ^8 P6 q5 l' c T
|