分享
 
 
 

如何使用动态代理实现AOP功能

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

一、使用的背景(也不能算是使用的背景,最多只能算是一个在什么条件下面我想到了使用动态代理实现AOP的拦截功能):

因为在项目中程序的结构是使用SOAP调用JNI,因此在SOAP服务端里面没有任何实现代码,仅仅是new一个JNI的对象,然后调用JNI对应的方法。但是在调用JNI方法之前需要对传进JNI的JavaBean进行初始化,而且还需要记录日志。而SOAP服务端的代码是通过ant自动生成的,需要对他进行手工的修改,在修改过程中发现每一个方法里面都是相同的:记录进入方法的日志、初始化JavaBean和记录退出方法的日志,这写东西都是通过拷贝粘贴来完成的,想到如果以后再加一个什么功能的时候又得每一个方法进行拷贝粘贴,而且方法的数量还不少,所以觉得这样来实现是不科学的。示例代码如下:

public class SOAP{

private JniInterface jni = null;

private Log log = 。。。;

public SOAP(){

jni=new JniClass();

}

/**方法A**/

public JavaBeanA aMethod(JavaBeanA javaBeanA){

log.debug("进入A方法");

//初始化JavaBean

Init(javaBeanA);

//调用JNI对应的方法

JavaBeanA result = jni.aMethod(javaBeanA);

log.debug("退出A方法");

return result;

}

……………………………………

……………………………………

等等,很多这样的方法

……………………………………

……………………………………

}

从示例代码里面可以看出,除了调用JNI对应的方法不同之外,其他的都是相同的代码,把所有的东西进行拷贝复制是不合理的。每当对SOAP进行修改,就必须将所有的方法重新拷贝粘贴。为了省去拷贝粘贴这一工序,所以使用动态代理实现AOP拦截共能。

二、实现AOP拦截

1. 定义Interceptor接口

public interface Interceptor {

//在调用之前调用该方法

public void before(InvokeJniInfo invInfo);

//在调用之后调用该方法

public void after(InvokeJniInfo invInfo);

//出现异常之后调用该方法

public void exceptionThrow(InvokeJniInfo invInfo);

}

2. 定义 InvokeJniInfo 类

在Interceptor接口中的InvokeJniInfo类,该类的定义如下:

public class InvokeJniInfo {

//被代理的对象

Object proxy;

//被调用的方法

Method method;

//被调用方法的参数列表

Object[] args;

//调用之后的结果

Object result;

//抛出的异常

Throwable exception;

public InvokeJniInfo(Object proxy,

Method method,

Object[] args,

Object result,

Throwable exception){

this.proxy = proxy;

this.method = method;

this.args = args;

this.result = result;

this.exception = exception;

}

…………………………………………………………

…………………………………………………………

所有成员的get/set方法

…………………………………………………………

…………………………………………………………

}

从该类的成员变量可以知道,这个类使用来将调用函数的基本信息如代理的对象,调用的方法,调用方法的参数等信息传递给Interceptor,使得在Interceptor 之中可以通过使用该对象作出相应的拦截。

3.实现一个抽象的拦截器AbstractInterceptor

该拦截器实现了Interceptor接口,它里面的方法全都是空的,其目的是当某些拦截器只是需要实现三个方法中的一个方法或者两个方法的时候,就可以继承该抽象类,覆盖需要的实现的方法就可以了。

4.实现日志记录拦截器LogInterceptor

该拦截器主要是实现在调用之前记录日志,调用之后记录日志和出现异常的时候记录日志。其代码如下:

public class LogInterceptor implements Interceptor {

private Log log = LogFactory.getLog(“初始化Log” );

public void before(InvokeJniInfo invInfo) {

//调用InvokeJniInfo对象的Method的getName方法获取方法名

log.debug("Enter the" + invInfo.getMethod().getName());

}

public void after(InvokeJniInfo invInfo) {

//调用InvokeJniInfo对象的Method的getName方法获取方法名

log.debug("Exit the" + invInfo.getMethod().getName());

}

public void exceptionThrow(InvokeJniInfo invInfo) {

//调用InvokeJniInfo对象的Method的getName方法获取方法名

log.error("Call the" + invInfo.getMethod().getName() + " has error!");

//调用InvokeJniInfo对象的Exception的getStackTrace方法获取具体异常并记录

log.error(invInfo.getException().getStackTrace());

}

}

5.实现初始化JavaBean拦截器InitParamsInterceptor

该类继承AbstractInterceptor,只需覆盖before方法即可。其代码如下:

public class InitParamsInterceptor extends AbstractInterceptor {

public void before(InvokeJniInfo invInfo) {

if(invInfo.getArgs().length>0){

//初始化第一个参数

InitContainsObjectNullUtil.initContainsOutParameter(invInfo.getArgs()[0]);

}

}

}

6.实现动态代理处理器InterceptorHandler

该类实现了java.lang.reflect.InvocationHandler接口。

public class InterceptorHandler implements InvocationHandler {

private static Log log = LogFactory.getLog(InterceptorHandler.class);

//拦截器列表

private List interceptors = null;

//存放原始对象

private Object orginalObject;

//使用Proxy返回一个对象。注意这里传进去的对象的对象必须实现一个接口

public Object bind(Object obj) {

this.orginalObject = obj;

return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj

.getClass().getInterfaces(), this);

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Object result = null;

Throwable ex = null;

InvokeJniInfo invInfo = new InvokeJniInfo(proxy,method,args,result,ex);

log.debug("Invoking Before Intercepors!");

//实现方法调用之前进行拦截的方法

invokeInterceptorBefor(invInfo);

try{

log.debug("Invoking Proxy Method!");

//调用方法

result = method.invoke(orginalObject,args);

invInfo.setResult(result);

log.debug("Invoking After method!");

//实现方法调用之后进行拦截的方法

invokeInterceptorAfter(invInfo);

}catch(Throwable tr){

invInfo.setException(tr);

log.error("Invoking exceptionThrow method!");

//实现出现异常进行拦截的方法

invokeInterceptorExceptionThrow(invInfo);

}

return result;

}

//获取拦截器列表

private synchronized List getIntercetors(){

if(null == interceptors){

interceptors = new ArrayList();

//添加日志记录拦截器

interceptors.add(new LogInterceptor());

//添加初始化JavaBean拦截器

interceptors.add(new InitParamsInterceptor());

//如果需要添加其他功能,可以很方便的添加其他的拦截器实现功能

}

return interceptors;

}

private void invokeInterceptorBefor(InvokeJniInfo invInfo){

List interceptors = getIntercetors();

int len = interceptors.size();

//遍历所有拦截器,并调用拦截器的before方法

for(int i = 0;i<len;i++){

((Interceptor)interceptors.get(i)).before(invInfo);

}

}

private void invokeInterceptorAfter(InvokeJniInfo invInfo){

List interceptors = getIntercetors();

int len = interceptors.size();

//遍历所有拦截器,并调用拦截器的after方法

for(int i = len - 1;i >= 0;i--){

((Interceptor)interceptors.get(i)).after(invInfo);

}

}

private void invokeInterceptorExceptionThrow(InvokeJniInfo invInfo){

List interceptors = getIntercetors();

int len = interceptors.size();

//遍历所有拦截器,并调用拦截器的exceptionThrow方法

for(int i = len - 1;i >= 0;i--){

((Interceptor)interceptors.get(i)).exceptionThrow(invInfo);

}

}

}

7.获取动态代理对象工厂InterceptorFactory

public class InterceptorFactory {

private static Log log = LogFactory.getLog(InterceptorFactory.class);

public static Object getClassInstance(String clzName) {

Class cls;

Object obj = null;

try {

cls = Class.forName(clzName);

obj = (Object) cls.newInstance();

} catch (Exception e) {

log.error(e.getStackTrace());

}

return obj;

}

public static Object getInterceptorProxyedObject(String clzName) {

InterceptorHandler aopHandler = new InterceptorHandler();

Object obj = getClassInstance(clzName);

return aopHandler.bind(obj);

}

}

8.修改以前的代码,使用动态代理实现

public class SOAP{

private JniInterface jni = null;

private Log log = 。。。;

public SOAP(){

jni=(JniInterface)InterceptorFactory.getInterceptorProxyedObject("JniClass");

}

/**方法A**/

public JavaBeanA aMethod(JavaBeanA javaBeanA){

return jni.aMethod(javaBeanA);

}

……………………………………

……………………………………

等等,很多这样的方法

……………………………………

……………………………………

}

从红色代码对比可以看出,省了很多代码。

三、总结

1. 必须彻底贯彻针对接口编成这一编成思想。

2. 明白了这个,是不是也明白了Spring的AOP的实现了?以及为什么要使用Spring的AOP的时候必须使用他的BeanFactory呢?

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有