我的Blog我做主^_^

走向一条通往JAVA的不归路...

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  64 随笔 :: 68 文章 :: 77 评论 :: 0 Trackbacks

Aspect Oriented Programming
AOP概念
Aspect Oriented Programming(AOP)是近来较为热门的一个话题。AOP,国内
大致译作“面向方面编程”。
“面向方面编程”,这样的名字并不是非常容易理解,且容易产生一些误导。笔者不止
一次听到类似“OOP/OOD11即将落伍,AOP是新一代软件开发方式”这样的发言。显然,
发言者并没有理解AOP的含义。
Aspect,没错,的确是“方面”的意思。不过,华语传统语义中的“方面”,大多数情
况下指的是一件事情的不同维度、或者说不同角度上的特性,比如我们常说:“这件事情要
从几个方面来看待”,往往意思是:需要从不同的角度来看待同一个事物。这里的“方面”,
指的是事务的外在特性在不同观察角度下的体现。
而在AOP中,Aspect的含义,可能更多的理解为“切面”比较合适。所以笔者更倾向
于“面向切面编程”的译法。
另外需要提及的是,AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种
设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,
以获得更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步
骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有
着本质的差异。
上面的陈述可能过于理论化,举个简单的例子,对于“雇员”这样一个业务实体进行封
装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相
关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。
同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP
对一个动作进行封装,则有点不伦不类。
换而言之,OOD/OOP面向名词领域,AOP面向动词领域。
AOP和OOD/OOP并不冲突,我们完全可以在一个应用系统中同时应用OOD/OOP和
AOP设计思想,通过OOD/OOP对系统中的业务对象进行建模,同时通过AOP对实体处理
过程中的阶段进行隔离处理。即使不是OOD/OOP,而是在传统的POP(面向过程编程)中,
AOP也能起到同样的作用。
将不同阶段领域加以分隔,这是否就算是AOP呢?
AOP还有另外一个重要特点:源码组成无关性。
11 OOD = Object Oriented Design OOP = Object Oriented Programming
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
倘若应用中通过某个具体的业务逻辑类实现了独立的权限检查,而请求调度方法通过预
编码调用这个权限模块实现权限管理。那么这也不算是AOP。对于AOP组件而言,很重要
的一点就是源码组成无关性,所谓源码组成无关性,体现在具体设计中就是AOP组件必须
与应用代码无关,简单来讲,就是应用代码可以脱离AOP组件独立编译。
为了实现源码组成无关性,AOP往往通过预编译方式(如AspectJ)和运行期动态代理
模式(如Spring AOP 和JBoss AOP)实现。
稍后章节中我们会就Spring Framework中的AOP实现机制进行更加深入的探讨。
下面先来看AOP中几个比较重要的概念:
1. 切面(Aspect)
切面,对象操作过程中的截面。这可能是AOP中最关键的一个术语。
我们首先来看一个应用开发中常见的切面:用户权限检查。大概只要是完整的应用,都
少不了用户权限检查这个模块,不同身份的用户可以做什么,不可以做什么,均由这个模块
加以判定。而这个模块调用的位置通常也比较固定:用户发起请求之后,执行业务逻辑之前。
针对权限检查这一模块进行分离,我们就得到了一个切面:
切面意义何在?
首先根据上例,假设我们实现了一个通用的权限检查模块,那么就可以在这层切面上进
行统一的集中式权限管理。而业务逻辑组件则无需关心权限方面的问题。也就是说,通过切
面,我们可以将系统中各个不同层次上的问题隔离开来,实现统一集约式处理。各切面只需
集中于自己领域内的逻辑实现。
这一方面使得开发逻辑更加清晰,专业化分工更加易于进行;另一方面,由于切面的隔
离,降低了耦合性,我们就可以在不同的应用中将各个切面组合使用,从而使得代码可重用
性大大增强。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
2. 连接点(JoinPoint)
程序运行过程中的某个阶段点。如某个方法调用,或者某个异常被抛出。
3. 处理逻辑(Advice)
在某个连接点所采用的处理逻辑
(这里的Advice,国内不少文案中翻译为“通知”,估计是源于金山词霸,与实际含义不符,因而这
里采用意译)
处理逻辑的调用模式通常有三种:
i. Around
在连接点前后插入预处理过程和后处理过程。
ii. Before
仅在连接点之前插入预处理过程。
iii. Throw
在连接点抛出异常时进行异常处理。
4. 切点(PointCut)
一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。
上述几个概念我们将在稍后的“AOP应用”一节中结合实际使用进行具体探讨。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOP in Spring
Spring中提供的内置AOP支持,是基于动态AOP机制实现。从技术角度来讲,所谓动
态AOP,即通过动态Proxy模式,在目标对象的方法调用前后插入相应的处理代码。
而Spring AOP中的动态Proxy模式,则是基于Java Dynamic Proxy(面向Interface)
和CGLib(面向Class)实现。
前面曾经提及,Spring Framework中的“事务管理”服务,实际上是借助AOP机制
完成。我们这里就以“事务管理”为例,对动态AOP的实现加以探讨,一方面对动态AOP
的实现原理加以探究,另一方面,也可以加深对Spring中事务管理机制的理解。
首先,我们来看基于Java Dynamic Proxy的AOP实现原理。
Dynamic Proxy 与Spring AOP
Dynamic Proxy是JDK 1.3版本中新引入的一种动态代理机制。它是Proxy模式的一
种动态实现版本。
我们先来看传统方式下一个Proxy的实现实例。
假设我们有一个UserDAO接口及其实现类UserDAOImp:
UserDAO.java:
public interface UserDAO {
public void saveUser(User user);
}
UserDAOImp.java:
public class UserDAOImp implements UserDAO{
public void saveUser(User user) {
……
}
}
UserDAOImp.saveUser方法中实现了针对User对象的数据库持久逻辑。
如果我们希望在UserDAOImp.saveUser方法执行前后追加一些处理过程,如启动/
提交事务,而不影响外部代码的调用逻辑,那么,增加一个Proxy类是个不错的选择:
UserDAOProxy.java
public class UserDAOProxy implements UserDAO {
private UserDAO userDAO;
public UserDAOProxy(UserDAO userDAO) {
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this.userDAO = userDAO;
}
public void saveUser(User user) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (
new InitialContext().lookup("java/tx")
);
userDAO.saveUser(user);
tx.commit();
} catch (Exception ex) {
if (null!=tx){
try {
tx.rollback();
}catch(Exception e) {
}
}
}
}
}
UserDAOProxy同样是UserDAO接口的实现,对于调用者而言,saveUser方法的使
用完全相同,不同的是内部实现机制已经发生了一些变化――我们在UserDAOProxy中为
UserDAO.saveUser方法套上了一个JTA事务管理的外壳。
上面是静态Proxy模式的一个典型实现。
现在假设系统中有20个类似的接口,针对每个接口实现一个Proxy,实在是个繁琐无
味的苦力工程。
Dynamic Proxy的出现,为这个问题提供了一个更加聪明的解决方案。
我们来看看怎样通过Dynamic Proxy解决上面的问题:
public class TxHandler implements InvocationHandler {
private Object originalObject;
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
if (!method.getName().startsWith("save")) {
UserTransaction tx = null;
try {
tx = (UserTransaction) (
new InitialContext().lookup("java/tx")
);
result = method.invoke(originalObject, args);
tx.commit();
} catch (Exception ex) {
if (null != tx) {
try {
tx.rollback();
} catch (Exception e) {
}
}
}
} else {
result = method.invoke(originalObject, args);
}
return result;
}
}
首先注意到,上面这段代码中,并没有出现与具体应用层相关的接口或者类引用。也就
是说,这个代理类适用于所有接口的实现。
其中的关键在两个部分:
1.
return Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
this);
java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型
(obj.getClass().getInterfaces())动态构造一个代理类实例返回,这个代理类是JVM
在内存中动态构造的动态类,它实现了传入的接口列表中所包含的所有接口。
这里也可以看出,Dynamic Proxy要求所代理的类必须是某个接口的实现
(obj.getClass().getInterfaces()不可为空),否则无法为其构造响应的动态类。这也
就是为什么Spring对接口实现类通过Dynamic Proxy实现AOP,而对于没有实现任何接口
的类通过CGLIB实现AOP机制的原因,关于CGLIB,请参见稍后章节的讨论。
2.
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
……
result = method.invoke(originalObject, args);
……
return result;
}
InvocationHandler.invoke方法将在被代理类的方法被调用之前触发。通过这个方
法中,我们可以在被代理类方法调用的前后进行一些处理,如代码中所示,
InvocationHandler.invoke方法的参数中传递了当前被调用的方法(Method),以及被
调用方法的参数。
同时,我们可以通过Method.invoke方法调用被代理类的原始方法实现。这样,我们
就可以在被代理类的方法调用前后大做文章。
在示例代码中,我们为所有名称以“save”开头的方法追加了JTA事务管理。
谈到这里,可以回忆一下Spring事务配置中的内容:
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
想必大家已经猜测到Spring事务管理机制的实现原理。
是的,只需通过一个Dynamic Proxy对所有需要事务管理的Bean进行加载,并根据配
置,在invoke方法中对当前调用的方法名进行判定,并为其加上合适的事务管理代码,那
么就实现了Spring式的事务管理。
当然,Spring中的AOP实现更为复杂和灵活,不过基本原理一致。
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
代码胜千言,下面是笔者在客户培训过程中编写的一个Dynamic Proxy based AOP
实现示例,非常简单,有兴趣的读者可以看看。
AOPHandler.java:
public class AOPHandler implements InvocationHandler {
private static Log logger = LogFactory.getLog(AOPHandler.class);
private List interceptors = null;
private Object originalObject;
/**
* 返回动态代理实例
* @param obj
* @return
*/
public Object bind(Object obj) {
this.originalObject = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj
.getClass().getInterfaces(), this);
}
/**
* 在Invoke方法中,加载对应的Interceptor,并进行
* 预处理(before)、后处理(after)以及异常处理(exceptionThrow)过程
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
Throwable ex = null;
InvocationInfo invInfo = new InvocationInfo(proxy, method, args,
result, ex);
logger.debug("Invoking Before Intercetpors!");
invokeInterceptorsBefore(invInfo);
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
try {
logger.debug("Invoking Proxy Method!");
result = method.invoke(originalObject, args);
invInfo.setResult(result);
logger.debug("Invoking After Method!");
invokeInterceptorsAfter(invInfo);
} catch (Throwable tr) {
invInfo.setException(tr);
logger.debug("Invoking exceptionThrow Method!");
invokeInterceptorsExceptionThrow(invInfo);
throw new AOPRuntimeException(tr);
}
return result;
}
/**
* 加载Interceptor
* @return
*/
private synchronized List getIntercetors() {
if (null == interceptors) {
interceptors = new ArrayList();
//Todo:读取配置,加载Interceptor实例
//interceptors.add(new MyInterceptor());
}
return interceptors;
}
/**
* 执行预处理方法
* @param invInfo
*/
private void invokeInterceptorsBefore(InvocationInfo invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
for (int i = 0; i < len; i++) {
((Interceptor) interceptors.get(i)).before(invInfo);
}
}
/**
* 执行后处理方法
* @param invInfo
*/
private void invokeInterceptorsAfter(InvocationInfo invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
for (int i = len - 1; i >= 0; i--) {
((Interceptor) interceptors.get(i)).after(invInfo);
}
}
/**
* 执行异常处理方法
* @param invInfo
*/
private void invokeInterceptorsExceptionThrow(InvocationInfo
invInfo) {
List interceptors = getIntercetors();
int len = interceptors.size();
for (int i = len - 1; i >= 0; i--) {
((Interceptor)
interceptors.get(i)).exceptionThrow(invInfo);
}
}
}
Interceptor.java:
public interface Interceptor {
public void before(InvocationInfo invInfo);
public void after(InvocationInfo invInfo);
public void exceptionThrow(InvocationInfo invInfo);
}
InvocationInfo.java:
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public class InvocationInfo {
Object proxy;
Method method;
Object[] args;
Object result;
Throwable Exception;
public InvocationInfo(Object proxy, Method method, Object[] args,
Object result, Throwable exception) {
super();
this.proxy = proxy;
this.method = method;
this.args = args;
this.result = result;
Exception = exception;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Throwable getException() {
return Exception;
}
public void setException(Throwable exception) {
Exception = exception;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getProxy() {
return proxy;
}
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public void setProxy(Object proxy) {
this.proxy = proxy;
}
}
AOPFactory.java:
public class AOPFactory {
private static Log logger = LogFactory.getLog(AOPFactory.class);
/**
* 根据类名创建类实例
* @param clzName
* @return
* @throws ClassNotFoundException
*/
public static Object getClassInstance(String clzName){
Class cls;
try {
cls = Class.forName(clzName);
return (Object)cls.newInstance();
} catch (ClassNotFoundException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
} catch (InstantiationException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
} catch (IllegalAccessException e) {
logger.debug(e);
throw new AOPRuntimeException(e);
}
}
/**
* 根据传入的类名,返回AOP代理对象
* @param clzName
* @return
*/
public static Object getAOPProxyedObject(String clzName){
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOPHandler txHandler = new AOPHandler();
Object obj = getClassInstance(clzName);
return txHandler.bind(obj);
}
}
MyInterceptor.java:
public class MyInterceptor implements Interceptor{
private static Log logger = LogFactory.getLog(MyInterceptor.class);
public void before(InvocationInfo invInfo) {
logger.debug("Pre-processing");
}
public void after(InvocationInfo invInfo) {
logger.debug("Post-processing");
}
public void exceptionThrow(InvocationInfo invInfo) {
logger.debug("Exception-processing");
}
}
Spring中Dynamic Proxy AOP实现类为:
org.springframework.aop.framework.JdkDynamicAopProxy
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
CGLib 与Spring AOP
上面曾经提过,Dynamic Proxy是面向接口的动态代理实现,其代理对象必须是某个
接口的实现。Dynamic Proxy通过在运行期构建一个此接口的动态实现类完成对目标对象
的代理(相当于在运行期动态构造一个UserDAOProxy,完成对UserDAOImp的代理任
务)。
而如果目标代理对象并未实现任何接口,那么Dynamic Proxy就失去了创建动态代理
类的基础依据。此时我们需要借助一些其他的机制实现动态代理机制。
Spring中,引入了CGLib作为无接口情况下的动态代理实现。
CGLib与Dynamic Proxy的代理机制基本类似,只是其动态生成的代理对象并非某个
接口的实现,而是针对目标类扩展的子类。
换句话说,Dynamic Proxy返回的动态代理类,是目标类所实现的接口的另一个实现
版本,它实现了对目标类的代理(如同UserDAOProxy与UserDAOImp的关系)。而CGLib
返回的动态代理类,则是目标代理类的一个子类(代理类扩展了UserDAOImp类)。
与Dynamic Proxy中的Proxy和InvocationHandler相对应,Enhancer和
MethodInterceptor在CGLib中负责完成代理对象创建和方法截获处理。
下面是通过CGLib进行动态代理的示例代码:
AOPInstrumenter.java:
public class AOPInstrumenter implements MethodInterceptor {
private static Log logger =
LogFactory.getLog(AOPInstrumenter.class);
private Enhancer enhancer = new Enhancer();
public Object getInstrumentedClass(Class clz) {
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
public Object intercept(
Object o,
Method method,
Object[] methodParameters,
MethodProxy methodProxy)
throws Throwable {
logger.debug("Before Method =>"+method.getName());
Object result = methodProxy.invokeSuper(o, methodParameters);
logger.debug("After Method =>"+method.getName());
return result;
}
}
测试代码:
AOPInstrumenter aopInst = new AOPInstrumenter();
UserDAOImp userDAO =
(UserDAOImp) aopInst.getInstrumentedClass(UserDAOImp.class);
User user = new User();
user.setName("Erica");
userDAO.saveUser(user);
有兴趣的读者可以利用CGLib对Dynamic Proxy中给出的AOP实现代码进行改造。
Spring中,基于CGLib的AOP实现位于:
org.springframework.aop.framework.Cglib2AopProxy
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
AOP 应用
前面介绍AOP概念的章节中,曾经以权限检查为例说明AOP切面的概念。
权限检查的确是AOP应用中一个热门话题,假设如果现在出现了一个设计完备的权限
管理组件,那么将是一件多么惬意的事情,我们只需要在系统中配置一个AOP组件,即可
完成以往需要大费周张才能完成的权限判定功能。
可惜目前还没有这样一个很完善的实现。一方面权限检查过于复杂多变,不同的业务系
统中的权限判定逻辑可能多种多样(如对于某些关键系统而言,很可能出现需要同时输入两
个人的密码才能访问的需求)。另一方面,就目前的AOP应用粒度而言,“权限管理”作为
一个切面尚显得过于庞大,需要进一步切分设计,设计复杂,实现难度较大。
目前最为实用的AOP应用,可能就是Spring中基于AOP实现的事务管理机制,也正是
这一点,使得Spring AOP大放异彩。
之前的内容中,我们大多围绕Spring AOP的实现原理进行探讨,这里我们围绕一个简
单的AOP Interceptor实例,看看Spring中AOP机制的应用与开发。
在应用系统开发过程中,我们通常需要对系统的运行性能有所把握,特别是对于关键业
务逻辑的执行效能,而对于执行效能中的执行时间,则可能是重中之重。
我们这里的实例的实现目标,就是打印出目标Bean中方法的执行时间。
首先,围绕开篇中提到的几个重要概念,我们来看看Spring中对应的实现。
1. 切点(PointCut)
一系列连接点的集合,它指明处理方式(Advice)将在何时被触发。
对于我们引用开发而言,“何时触发”的条件大多是面向Bean的方法进行制定。实
际上,只要我们在开发中用到了Spring的配置化事务管理,那么就已经进行了PointCut
设置,我们可以指定对所有save开头的方法进行基于AOP的事务管理:
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
</props>
</property>
同样,对于我们的AOP组件而言,我们也可以以方法名作为触发判定条件。
我们可以通过以下节点,为我们的组件设定触发条件。
<bean id="myPointcutAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdv
isor">
<property name="advice">
<ref local="MyInterceptor" />
</property>
<property name="patterns">
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
<list>
<value>.*do.*</value>
<value>.*execute.*</value>
</list>
</property>
</bean>
RegexpMethodPointcutAdvisor是Spring中提供的,通过逻辑表达式指定方法
判定条件的支持类。其中的逻辑表达式解析采用了Apache ORO组件实现,关于逻
辑表达式的语法请参见Apache ORO文档。
上面我们针对MyInterceptor设定了一个基于方法名的触发条件,也就是说,当
目标类的指定方法运行时,MyInterceptor即被触发。
MyInterceptor是我们对应的AOP逻辑处理单元,也就是所谓的Advice。
2. Advice
Spring中提供了以下几种Advice:
1. Interception around advice
Spring中最基本的Advice类型,提供了针对PointCut的预处理、后处理过程
支持。
我们将使用Interception around advice完成这里的实例。
2. Before advice
仅面向了PointCut的预处理。
3. Throws advice
仅面向PointCut的后处理过程中的异常处理。
4. After Returning advice
仅面向PointCut返回后的后处理过程。
5. Introduction advice
Spring中较为特殊的一种Advice,仅面向Class层面(而不像上述Advice面
向方法层面)。通过Introduction advice我们可以实现多线程访问中的类锁
定。
Spring中采用了AOP联盟(AOP Alliance)12的通用AOP接口(接口定义位于
aopalliance.jar)。这里我们采用aopalliance.jar中定义的MethodInterceptor作为
我们的Advice实现接口:
public class MethodTimeCostInterceptor implements
MethodInterceptor,
Serializable {
protected static final Log logger = LogFactory
12 http://aopalliance.sourceforge.net/
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
.getLog(MethodTimeCostInterceptor.class);
public Object invoke(MethodInvocation invocation) throws
Throwable {
long time = System.currentTimeMillis();
Object rval = invocation.proceed();
time = System.currentTimeMillis() - time;
logger.info("Method Cost Time => " + time + " ms");
return rval;
}
}
对应配置如下:
<bean id="MyInterceptor"
class="net.xiaxin.interceptors.MethodTimeCostInterceptor"
/>
除此之外,我们还需要定义一个Spring AOP ProxyFactory用以加载执行AOP组件。
定义如下:
<bean id="myAOPProxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>net.xiaxin.ITest</value>
</property>
<!—是否强制使用CGLIB进行动态代理
<property name="proxyTargetClass">
<value>true</value>
</property>
-->
<property name="target">
<ref local="test" />
</property>
<property name="interceptorNames">
<value>myPointcutAdvisor</value>
</property>
SpringFrameWork Developer’s Guide Version 0.6
October 8, 2004 So many open source projects. Why not Open your Documents?
</bean>
<bean id="test" class="net.xiaxin.Test"/>
其中的test是我们用于测试的一个类,它实现了ITest接口。
public interface ITest {
public abstract void doTest();
public abstract void executeTest();
}
public class Test implements ITest {
public void doTest(){
for (int i=0;i<10000;i++){}
}
public void executeTest(){
for (int i=0;i<25000;i++){}
}
}
通过以上工作,我们的MyInterceptor即被加载,并将在Test.doTest和
Test.executeTest方法调用时被触发,打印出这两个方法的执行时间。
public void testAOP() {
ApplicationContext ctx=new
FileSystemXmlApplicationContext("bean.xml");
ITest test = (ITest) ctx.getBean("myAOPProxy");
test.doTest();
test.executeTest();
}
引自:http://hi.baidu.com/zbzb/blog/item/0d6fa7ec0823c63f279791d8.html



posted on 2007-11-13 13:47 java_蝈蝈 阅读(556) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: