您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)Java中怎么利用動態(tài)代理實(shí)現(xiàn)AOP功能,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
一、Java編程使用的背景
也不能算是使用的背景,最多只能算是一個(gè)在什么條件下面我想到了使用動態(tài)代理實(shí)現(xiàn)AOP的攔截功能):因?yàn)樵陧?xiàng)目中程序的結(jié)構(gòu)是使用SOAP調(diào)用JNI,因此在SOAP服務(wù)端里面沒有任何實(shí)現(xiàn)代碼,僅僅是new一個(gè)JNI的對象,然后調(diào)用JNI對應(yīng)的方法。但是在調(diào)用JNI方法之前需要對傳進(jìn)JNI的JavaBean進(jìn)行初始化,而且還需要記錄日志。而SOAP服務(wù)端的代碼是通過ant自動生成的,需要對他進(jìn)行手工的修改,在修改過程中發(fā)現(xiàn)每一個(gè)方法里面都是相同的:記錄進(jìn)入方法的日志、初始化JavaBean和記錄退出方法的日志,這寫東西都是通過拷貝粘貼來完成的,想到如果以后再加一個(gè)什么功能的時(shí)候又得每一個(gè)方法進(jìn)行拷貝粘貼,而且方法的數(shù)量還不少,所以覺得這樣來實(shí)現(xiàn)是不科學(xué)的。示例代碼如下:
public class SOAP{ private JniInterface jni = null; private Log log = 。。。; public SOAP(){ jni=new JniClass(); } /**方法A**/ public JavaBeanA aMethod(JavaBeanA javaBeanA){ log.debug("進(jìn)入A方法"); //初始化JavaBean Init(javaBeanA); //調(diào)用JNI對應(yīng)的方法 JavaBeanA result = jni.aMethod(javaBeanA); log.debug("退出A方法"); return result; } …………………………………… …………………………………… 等等,很多這樣的方法 …………………………………… …………………………………… }
從示例代碼里面可以看出,除了調(diào)用JNI對應(yīng)的方法不同之外,其他的都是相同的代碼,把所有的東西進(jìn)行拷貝復(fù)制是不合理的。每當(dāng)對SOAP進(jìn)行修改,就必須將所有的方法重新拷貝粘貼。為了省去拷貝粘貼這一工序,所以使用動態(tài)代理實(shí)現(xiàn)AOP攔截共能。
二、實(shí)現(xiàn)AOP攔截
1.定義Interceptor接口
public interface Interceptor { //在調(diào)用之前調(diào)用該方法 public void before(InvokeJniInfo invInfo); //在調(diào)用之后調(diào)用該方法 public void after(InvokeJniInfo invInfo); //出現(xiàn)異常之后調(diào)用該方法 public void exceptionThrow(InvokeJniInfo invInfo); }
2. 定義 InvokeJniInfo 類
在Interceptor接口中的InvokeJniInfo類,該類的定義如下:
public class InvokeJniInfo { //被代理的對象 Object proxy; //被調(diào)用的方法 Method method; //被調(diào)用方法的參數(shù)列表 Object[] args; //調(diào)用之后的結(jié)果 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方法
…………………………………………………………
…………………………………………………………
}
從該類的成員變量可以知道,這個(gè)類使用來將調(diào)用函數(shù)的基本信息如代理的對象,調(diào)用的方法,調(diào)用方法的參數(shù)等信息傳遞給Interceptor,使得在Interceptor 之中可以通過使用該對象作出相應(yīng)的攔截。
3.實(shí)現(xiàn)一個(gè)抽象的攔截器AbstractInterceptor
該攔截器實(shí)現(xiàn)了Interceptor接口,它里面的方法全都是空的,其目的是當(dāng)某些攔截器只是需要實(shí)現(xiàn)三個(gè)方法中的一個(gè)方法或者兩個(gè)方法的時(shí)候,就可以繼承該抽象類,覆蓋需要的實(shí)現(xiàn)的方法就可以了。
4.實(shí)現(xiàn)日志記錄攔截器LogInterceptor
該攔截器主要是實(shí)現(xiàn)在調(diào)用之前記錄日志,調(diào)用之后記錄日志和出現(xiàn)異常的時(shí)候記錄日志。其代碼如下:
public class LogInterceptor implements Interceptor {private Log log = LogFactory.getLog(“初始化Log” );public void before(InvokeJniInfo invInfo) {//調(diào)用InvokeJniInfo對象的Method的getName方法獲取方法名log.debug("Enter the" + invInfo.getMethod().getName());}public void after(InvokeJniInfo invInfo) {//調(diào)用InvokeJniInfo對象的Method的getName方法獲取方法名log.debug("Exit the" + invInfo.getMethod().getName());}public void exceptionThrow(InvokeJniInfo invInfo) {//調(diào)用InvokeJniInfo對象的Method的getName方法獲取方法名log.error("Call the" + invInfo.getMethod().getName() + " has error!");//調(diào)用InvokeJniInfo對象的Exception的getStackTrace方法獲取具體異常并記錄log.error(invInfo.getException().getStackTrace()); } }
5.實(shí)現(xiàn)初始化JavaBean攔截器InitParamsInterceptor
該類繼承AbstractInterceptor,只需覆蓋before方法即可。其代碼如下:
public class InitParamsInterceptor extends AbstractInterceptor { public void before(InvokeJniInfo invInfo) { if(invInfo.getArgs().length>0){
//初始化***個(gè)參數(shù)
InitContainsObjectNullUtil.initContainsOutParameter(invInfo.getArgs()[0]); } } }
6.實(shí)現(xiàn)動態(tài)代理處理器InterceptorHandler
該類實(shí)現(xiàn)了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返回一個(gè)對象。注意這里傳進(jìn)去的對象的對象必須實(shí)現(xiàn)一個(gè)接口
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!");
//實(shí)現(xiàn)方法調(diào)用之前進(jìn)行攔截的方法
invokeInterceptorBefor(invInfo); try{ log.debug("Invoking Proxy Method!"); //調(diào)用方法 result = method.invoke(orginalObject,args); invInfo.setResult(result); log.debug("Invoking After method!");
//實(shí)現(xiàn)方法調(diào)用之后進(jìn)行攔截的方法
invokeInterceptorAfter(invInfo); }catch(Throwable tr){ invInfo.setException(tr); log.error("Invoking exceptionThrow method!");
//實(shí)現(xiàn)出現(xiàn)異常進(jìn)行攔截的方法
invokeInterceptorExceptionThrow(invInfo); } return result; }
//獲取攔截器列表
private synchronized List getIntercetors(){ if(null == interceptors){ interceptors = new ArrayList();
//添加日志記錄攔截器
interceptors.add(new LogInterceptor());
//添加初始化JavaBean攔截器
interceptors.add(new InitParamsInterceptor());
//如果需要添加其他功能,可以很方便的添加其他的攔截器實(shí)現(xiàn)功能
} return interceptors; } private void invokeInterceptorBefor(InvokeJniInfo invInfo){ List interceptors = getIntercetors(); int len = interceptors.size();
//遍歷所有攔截器,并調(diào)用攔截器的before方法
for(int i = 0;i((Interceptor)interceptors.get(i)).before(invInfo); } } private void invokeInterceptorAfter(InvokeJniInfo invInfo){ List interceptors = getIntercetors(); int len = interceptors.size();
//遍歷所有攔截器,并調(diào)用攔截器的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();
//遍歷所有攔截器,并調(diào)用攔截器的exceptionThrow方法
for(int i = len - 1;i >= 0;i--){ ((Interceptor)interceptors.get(i)).exceptionThrow(invInfo); } } }
7.獲取動態(tài)代理對象工廠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.修改以前的代碼,使用動態(tài)代理實(shí)現(xiàn) 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); }
看完上述內(nèi)容,你們對Java中怎么利用動態(tài)代理實(shí)現(xiàn)AOP功能有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。