spring中AOP的实现就是通过动态代理来实现的。动态代理的实现在上篇blog中已经涉及。Spring中目前最为实用的AOP应用,非用其实现的事务管理机制莫属。也正是这一点,使得Spring AOP大方异彩。/ T/ l6 h' d& J' o3 r3 W7 V
那么我们继续围绕上节的例子来探讨一下Spring中AOP机制的应用与开发。 首先,看看AOP中几个基本的概念对应在AOP中的实现:
2 @4 s, R5 L3 Q' x9 c- v- A? 切点(PointCut)
! W! i: K- H% J: z4 K 一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。 $ x( \1 Q6 E& |3 F- W1 h
对于我们开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。像Spring的配置化事务管理时针对方法名称可进行PointCut设置,从而指定对所有以声明字符开头的方法进行基于AOP的事务管理。那么同样,对于我们自己实现的AOP组件而言,我们也可以以方法名作为触发判定条件。7 ?0 k! `6 Z7 S7 W
我们可以通过在XML配置文件中配置以下节点,为我们的组件设定触发条件。
3 z4 Y" k1 f0 b6 \ n1 y) W<bean id="myPointcutAdvisor"
4 D Y5 s' o6 A& y$ Y, g) |7 w) f) Dclass="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> + L( }/ U) U; F" v* g2 x
<property name="advice">
' l0 x0 a' y. l5 C) M: M<ref local="MyInterceptor" />
/ k! @: A" N6 s0 B: O3 j( X# i</property>
5 U/ h8 _4 M0 h, |<property name="patterns"> & \' B0 [9 S/ \0 i! N( [% s2 j
<list> ( M: ]: N! b/ U% R5 W9 g( G {. Z7 |7 B
<value>.*save.*</value> + o, z+ ~) H; u# I% C1 Q
<value>.*do.*</value>
0 i% b( G* f$ ^+ |</list>
T6 k5 @" Q1 a3 F6 b</property>
, ~* C! c% ?& m' t8 e</bean> 上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当目标类的指定方法运行时,MyInterceptor即被触发。 - p) P9 `' b* |2 Z' ~7 Q6 E4 D3 F) C
? 处理方式(Advice) - L: e% R! ^9 w3 l! Z
也就是说要实现一个Interceptor,以供在连接点时触发。Spring中采用了AOP联盟(AOP Alliance)的通用AOP接口(接口定义位aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为我们的Advice实现接口。那么我们上节例子中的处理方式应实现为如下Interceptor:
% {' }4 H+ } [! u5 l* Tpackage test.aop.spring; ; Z* i3 Y2 M2 Y
import java.util.logging.Logger; - ` ^& w! ?2 ~1 |
import org.aopalliance.intercept.MethodInterceptor;
- V) U7 o1 p) R" Z$ ^( [, {import org.aopalliance.intercept.MethodInvocation; /**
% t1 }. g8 S2 p5 g8 _7 z3 W* @author xkf * R7 l1 X h! e& h. k2 R* z2 u& S
**/ . ?4 Z9 w7 F; D% Y
public class LockInterceptor implements MethodInterceptor { - c& B3 z( Y$ K8 @$ B6 R9 V
private Logger logger = Logger.getLogger(this.getClass().getName());
( l' G$ I* b! l2 {; e9 f. kpublic Object invoke(MethodInvocation invocation) throws Throwable {
9 c& {2 t4 B5 a# }6 N3 R9 S// TODO Auto-generated method stub 3 K3 @1 @: ^9 W/ ^& s% N# t& c
lock(); 9 Y2 H- B* Y2 m& @1 B# J
Object ret= invocation.proceed(); 7 u! N, o4 f: `
unlock(); : K# q$ t5 A" ~5 J: x' N
return ret;
5 ?# c+ S2 F. C5 G& G; n} ! h$ e# @8 ?7 V
private void lock(){
5 l- I2 W/ Z, Y+ n0 u& llogger.info("lock domain object..."); 5 j0 e; f& W- o5 t. l+ V O
}
: n: ?0 j9 ]; O- K# p3 uprivate void unlock(){ 9 A6 Y8 S+ |$ L: O( M
logger.info("unlock domain object..."); ; }5 ?5 ]6 a, a; k7 W
} * u+ [, r3 A/ p v
}
; K1 k' T* j4 K5 a' C 实现后,对应的Interceptor实现类在配置文件中的体现如下: ! e- P0 Z; P3 o- f
<bean id="MyInterceptor" class="test.aop.spring.LockInterceptor"/>
# Y% ]# n4 q- @7 P 最后,我们还需要定义一个Spring AOP ProxyFactory用于加载执行AOP组件,并且需要将Advice通过IOC的方式注入到接口以及实现类。 ) \- w j- W* _/ c Y9 |
对应的配置文件应如下配置从而实现这些内容:
4 Y) n) l' b3 n6 |; j9 {% ~<bean id="myAOPProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
5 L( g9 W, v3 w+ W" O<property name="proxyInterfaces">
$ W: C& c5 X* M6 d3 S5 ? \<value>test.aop.spring.DomainObjDAO</value>
9 @" P' C1 V$ _& a6 d! K/ I</property> 4 o! F5 y) G: Q# B1 v
<property name="target">
( R% N6 \$ j* G0 I# [4 b$ [# y' P5 G<ref local="impl" /> r. ?% K: t9 T! O2 ~& J2 \
</property> . Q0 m. f+ X' U9 j* N( H* s
<property name="interceptorNames">
5 e. }) x. E4 l<value>myPointcutAdvisor</value>
6 x3 t. o0 _8 l0 Y5 ]; P</property>
4 D) i' G) H3 f: T* r</bean> 3 A+ ^; z, v2 O, g2 n% l @
<bean id="impl" class="test.aop.spring.DomainObjDAOImpl"/> 6 _: w3 B! [, I6 ^
万事大吉!写一个TestCase来看一下运行结果:
6 O' J" J! T: G& f2 m1 rpackage test.aop.spring; import junit.framework.TestCase;
$ T. v/ b! M# E# T \import org.springframework.context.ApplicationContext; , U7 r# ]! x9 a: V3 c
import org.springframework.context.support.FileSystemXmlApplicationContext; /** ! T, O& t6 r( h4 S
* @author xkf ! c7 p. {% q* H
*/ ; n+ }) _9 ^/ U% b( I
public class SpringTestCase extends TestCase {
" \0 \( u5 V8 uDomainObjDAO test=null; protected void setUp() throws Exception {
, l; C* ?% r! r7 F$ Msuper.setUp(); 2 `1 Y( h8 X" E9 A5 X( [/ t, A
ApplicationContext ctx=new FileSystemXmlApplicationContext("test/Bean.xml"); 2 D6 `4 d2 S3 N" z" I
test = (DomainObjDAO) ctx.getBean("myAOPProxy");
: s' S+ V$ h, Q* {. M8 I6 q/ C1 o, W% L} protected void tearDown() throws Exception {
+ i. U! K9 Q& Z% ]super.tearDown();
0 ]: ?! W* w7 ?: a; Z0 ^} 0 L$ P3 B) j$ ?1 q. R6 {7 Q4 H
public void testSave(){
?" x& u+ j) b) X# ftest.save();
8 j; n( @1 ?( m' Q; z0 [# M& D} % c4 }# e* [; }+ M2 ^
} " M8 _2 @3 v3 j* k
运行结果如下: ( w7 X7 O$ Y, N* F; g5 w5 A
信息: Creating shared instance of singleton bean ''MyInterceptor''
& V$ @: ?: s5 D7 e) a2004-12-7 23:50:11 test.aop.spring.LockInterceptor lock
) u! Q( o) N, J- [. B* u信息: lock domain object...
& ?& ~4 ]4 z! }! N$ L8 `* P+ U- t# Msaving domain object...... # D: {( \9 a1 y! y+ \; E2 q1 L7 o) r5 q
2004-12-7 23:50:11 test.aop.spring.LockInterceptor unlock
1 ?+ i& @ ?% @3 T信息: unlock domain object... OK!至此,我们已经探讨了AOP动态代理的实现以及其在Spring中的应用,接下来的Blog中我将会关注Spring中事务以及持久化的实现。
' L( k* ~5 l0 @; `5 U |