spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。 k! d. T, I0 y p. f
那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
/ Y9 V" D* j6 N" N( {0 ]? 切点(PointCut)
3 D4 h4 D9 V7 k7 r 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 0 X8 g, ?& I: T4 h
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。
% d) p3 @9 q% B3 R我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。 8 Q# v: R9 n. x
<bean id="myPointcutAdvisor" / i- ]/ ]# l8 V. X. b& n
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
6 _) S) A1 A% w3 k6 M<property name="advice">
& w4 {# [5 K( ?9 w6 t% H& w- U/ M<ref local="MyInterceptor" /> + e9 F8 ~9 ~4 u- t3 Y
</property>
1 m z r8 y8 k% q! d<property name="patterns"> % \1 ]' \4 Z$ P+ O+ f1 M
<list>
0 U' k3 R3 V: a<value>.*save.*</value>
6 H8 N1 e8 e# l- v2 O<value>.*do.*</value>
0 \( L: v( ?) m o8 }</list> ; N- o( K; l( R% Q) ^2 l
</property> # \* y! ~/ P$ z. ~, i
</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。
/ Z% L. y3 M8 r9 N3 U. u0 C+ | ? 处理方式(Advice) + U8 A/ r& } ?( P# }$ W" B" q
也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:' j8 |) h# X5 u$ v$ w
package test.aop.spring;
- ^ e9 t# q; H+ F) `" timport java.util.logging.Logger; ; g) j+ P$ X$ o p
import org.aopalliance.intercept.MethodInterceptor; 8 g2 @# x- ?: C3 G$ I* v" K
import org.aopalliance.intercept.MethodInvocation; /** % ~, W( I2 {/ E, R3 S* t
* @author xkf x3 _; j P0 `* D8 A- B
**/ : }4 W# d$ m! A
public class LockInterceptor implements MethodInterceptor {
- L6 @5 ]1 Z: T" v* _3 A# v cprivate Logger logger = Logger.getLogger(this.getClass().getName()); $ ]/ L3 X+ g$ G: A! `
public Object invoke(MethodInvocation invocation) throws Throwable {
" B+ Z) |, F: L* L h4 _/ m3 N// TODO Auto-generated method stub - i; Y6 M0 ^# |; B9 }( u$ }1 |+ U
lock(); 8 U% E2 q2 h2 X( g7 W( U
Object ret= invocation.proceed();
* X" ?9 x4 c$ p6 n4 r8 w4 p2 Q" Lunlock(); & i& a1 s' U1 r# K# S
return ret;
7 U: k# c0 i0 A# {/ r}
0 H1 Y( v5 d1 G+ ^private void lock(){ * `4 }, h+ O: ~$ J6 F7 H
logger.info("lock domain object...");
* P7 r. D N& f4 L/ S0 U} 2 N2 K% M+ O% g/ T
private void unlock(){ $ |( G: Q" |% s" |) I" \
logger.info("unlock domain object...");
?9 f% w" X6 o4 G}
4 P& S$ y3 I& l) j7 p5 P( E: C}
3 C- j8 {* E8 ^. X% {9 R 实现后,对应的Interceptor实现类在配置文件中的体现如下: + @% M9 r$ e2 n- Z! A5 m
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/> 6 F4 i3 ?+ Y* v8 B: f
最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。
7 N, @6 k# }# |, a7 ]/ z9 D7 q, j2 Q 对应的配置文件应如下配置从而实现这些内容: 0 V1 ]8 C# V3 n' f' R
<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">( A1 r9 ]; P$ F
<property name="proxyInterfaces"> 5 a3 j0 B: W2 B c8 o
<value>test.aop.spring.DomainObjDAO</value> $ O( Y" J$ g) R4 W
</property> ( p- n( i1 i v" X- W9 ^5 p% Z
<property name="target">
0 Q2 L( G4 |9 r5 V }<ref local="impl" /> 0 w& x- A$ G' d2 F- Z4 M* O
</property> 6 b, p* v! O ~! C x' w1 Q
<property name="interceptorNames">
: a: \- Y% @- |% H3 |0 |3 I0 x<value>myPointcutAdvisor</value>
; A+ M5 N, ~! v6 h G9 i! l</property>
/ M* U) {2 I; p+ ?( }</bean> r3 V ?- k+ G) _3 n6 ~
<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/> 9 k# n5 B. u W9 @, l
万事大吉!写一个TestCase来看一下运行结果:
0 N3 c/ E6 J/ e4 K2 tpackage test.aop.spring; import junit.framework.TestCase;
. b6 P$ x, E- K1 mimport org.springframework.context.ApplicationContext; : y2 Q, X4 i/ k& h. ~
import org.springframework.context.support.FileSystemXmlApplicationContext; /**
- D/ \, P9 x9 E8 a2 D! P* @author xkf
' \! J* X" T8 v2 e( l' O& ]*/ / S* `$ }; a8 u1 A; ]$ Z
public class SpringTestCase extends TestCase {
" J* o8 @3 ` m( h/ g. e% ? m* NDomainObjDAO test=null; protected void setUp() throws Exception { 5 b1 Z0 Y( s1 ^3 i. @2 L
super.setUp(); ^3 B- J, g- w: C( _. h) o
ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml");
/ O: L4 T" `! ]test = (DomainObjDAO) ctx.getBean("myAOPProxy"); 3 @4 w: u8 x& ]' j! k; x
} protected void tearDown() throws Exception {
, G+ i. k6 c) J, h, r: S) R7 b- rsuper.tearDown(); 9 F! Z; n! _. ^+ T, F& S; g
} * O# j$ j: D! M
public void testSave(){ % q9 q) N0 ?6 v5 u" p5 r2 H" }
test.save();
; r) h: u9 o5 \ Q, ]; Q+ }}
* l5 F. Z* |! a0 \+ B3 J}
B- h3 D b2 E# F; k" d# _运行结果如下:
9 N; T; P- d& x4 Q! t: ]) v; G" D4 B信息: Creating shared instance of singleton bean ''MyInterceptor'' * `: o+ }3 a+ S4 @, V% e( l, M4 H
2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock , w+ H' l# s+ ~- C
信息: lock domain object...
6 l) [0 p. @, j4 Y. z0 Ksaving domain object......
% i& R @0 M6 a. [2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock - G$ E- D, d9 v' H
信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。 " o, c1 i, [$ W: I
|