自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java編程中使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP功能

開(kāi)發(fā) 后端
本文詳細(xì)介紹了Java編程中使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP功能,AOP是OOP的延續(xù),是Aspect Oriented Programming的縮寫(xiě),意思是面向切面編程。

一、Java編程使用的背景

也不能算是使用的背景,最多只能算是一個(gè)在什么條件下面我想到了使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP的攔截功能):因?yàn)樵陧?xiàng)目中程序的結(jié)構(gòu)是使用SOAP調(diào)用JNI,因此在SOAP服務(wù)端里面沒(méi)有任何實(shí)現(xiàn)代碼,僅僅是new一個(gè)JNI的對(duì)象,然后調(diào)用JNI對(duì)應(yīng)的方法。但是在調(diào)用JNI方法之前需要對(duì)傳進(jìn)JNI的JavaBean進(jìn)行初始化,而且還需要記錄日志。而SOAP服務(wù)端的代碼是通過(guò)ant自動(dòng)生成的,需要對(duì)他進(jìn)行手工的修改,在修改過(guò)程中發(fā)現(xiàn)每一個(gè)方法里面都是相同的:記錄進(jìn)入方法的日志、初始化JavaBean和記錄退出方法的日志,這寫(xiě)東西都是通過(guò)拷貝粘貼來(lái)完成的,想到如果以后再加一個(gè)什么功能的時(shí)候又得每一個(gè)方法進(jìn)行拷貝粘貼,而且方法的數(shù)量還不少,所以覺(jué)得這樣來(lái)實(shí)現(xiàn)是不科學(xué)的。示例代碼如下:  

  1. public class SOAP{   
  2.  
  3. private JniInterface jni = null;   
  4.  
  5. private Log log = 。。。;   
  6.  
  7. public SOAP(){   
  8.  
  9. jni=new JniClass();   
  10.  
  11. }   
  12.  
  13.  
  14. /**方法A**/   
  15.  
  16. public JavaBeanA aMethod(JavaBeanA javaBeanA){   
  17.  
  18. log.debug("進(jìn)入A方法");   
  19.  
  20. //初始化JavaBean   
  21.  
  22. Init(javaBeanA);   
  23.  
  24. //調(diào)用JNI對(duì)應(yīng)的方法   
  25.  
  26. JavaBeanA result = jni.aMethod(javaBeanA);   
  27.  
  28. log.debug("退出A方法");   
  29.  
  30. return result;   
  31.  
  32. }   
  33.  
  34. ……………………………………   
  35.  
  36. ……………………………………   
  37.  
  38. 等等,很多這樣的方法   
  39.  
  40. ……………………………………   
  41.  
  42. ……………………………………   
  43.  
  44. }   
  45.  

從示例代碼里面可以看出,除了調(diào)用JNI對(duì)應(yīng)的方法不同之外,其他的都是相同的代碼,把所有的東西進(jìn)行拷貝復(fù)制是不合理的。每當(dāng)對(duì)SOAP進(jìn)行修改,就必須將所有的方法重新拷貝粘貼。為了省去拷貝粘貼這一工序,所以使用動(dòng)態(tài)代理實(shí)現(xiàn)AOP攔截共能。

二、實(shí)現(xiàn)AOP攔截

1.定義Interceptor接口

  1. public interface Interceptor {   
  2.  
  3. //在調(diào)用之前調(diào)用該方法   
  4.  
  5. public void before(InvokeJniInfo invInfo);   
  6.  
  7. //在調(diào)用之后調(diào)用該方法   
  8.  
  9. public void after(InvokeJniInfo invInfo);   
  10.  
  11. //出現(xiàn)異常之后調(diào)用該方法   
  12.  
  13. public void exceptionThrow(InvokeJniInfo invInfo);   
  14.  
  15. }   

2. 定義 InvokeJniInfo 類(lèi)

在Interceptor接口中的InvokeJniInfo類(lèi),該類(lèi)的定義如下:

  1. public class InvokeJniInfo {   
  2.  
  3. //被代理的對(duì)象   
  4.  
  5. Object proxy;   
  6.  
  7. //被調(diào)用的方法   
  8.  
  9. Method method;   
  10.  
  11. //被調(diào)用方法的參數(shù)列表   
  12.  
  13. Object[] args;   
  14.  
  15. //調(diào)用之后的結(jié)果   
  16.  
  17. Object result;   
  18.  
  19. //拋出的異常   
  20.  
  21. Throwable exception;   
  22.  
  23.  
  24. public InvokeJniInfo(Object proxy,   
  25.  
  26. Method method,   
  27.  
  28. Object[] args,   
  29.  
  30. Object result,   
  31.  
  32. Throwable exception){   
  33.  
  34. this.proxy = proxy;   
  35.  
  36. this.method = method;   
  37.  
  38. this.args = args;   
  39.  
  40. this.result = result;   
  41.  
  42. this.exception = exception;   
  43.  
  44. }   
  45.  
  46. …………………………………………………………   
  47.  
  48. …………………………………………………………   

所有成員的get/set方法

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

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

}

從該類(lèi)的成員變量可以知道,這個(gè)類(lèi)使用來(lái)將調(diào)用函數(shù)的基本信息如代理的對(duì)象,調(diào)用的方法,調(diào)用方法的參數(shù)等信息傳遞給Interceptor,使得在Interceptor 之中可以通過(guò)使用該對(duì)象作出相應(yīng)的攔截。


3.實(shí)現(xiàn)一個(gè)抽象的攔截器AbstractInterceptor

該攔截器實(shí)現(xiàn)了Interceptor接口,它里面的方法全都是空的,其目的是當(dāng)某些攔截器只是需要實(shí)現(xiàn)三個(gè)方法中的一個(gè)方法或者兩個(gè)方法的時(shí)候,就可以繼承該抽象類(lèi),覆蓋需要的實(shí)現(xiàn)的方法就可以了。

4.實(shí)現(xiàn)日志記錄攔截器LogInterceptor

該攔截器主要是實(shí)現(xiàn)在調(diào)用之前記錄日志,調(diào)用之后記錄日志和出現(xiàn)異常的時(shí)候記錄日志。其代碼如下:

  1. public class LogInterceptor implements Interceptor {

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

  3. public void before(InvokeJniInfo invInfo) {

  4. //調(diào)用InvokeJniInfo對(duì)象的Method的getName方法獲取方法名

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

  6. }

  7. public void after(InvokeJniInfo invInfo) {

  8. //調(diào)用InvokeJniInfo對(duì)象的Method的getName方法獲取方法名

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

  10. }

  11. public void exceptionThrow(InvokeJniInfo invInfo) {

  12. //調(diào)用InvokeJniInfo對(duì)象的Method的getName方法獲取方法名

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

  14. //調(diào)用InvokeJniInfo對(duì)象的Exception的getStackTrace方法獲取具體異常并記錄

  15. log.error(invInfo.getException().getStackTrace());   
  16. }   
  17.  
  18. }   

5.實(shí)現(xiàn)初始化JavaBean攔截器InitParamsInterceptor

該類(lèi)繼承AbstractInterceptor,只需覆蓋before方法即可。其代碼如下:

  1. public class InitParamsInterceptor extends AbstractInterceptor {   
  2.  
  3.  
  4. public void before(InvokeJniInfo invInfo) {   
  5.  
  6. if(invInfo.getArgs().length>0){   

//初始化***個(gè)參數(shù)

  1. InitContainsObjectNullUtil.initContainsOutParameter(invInfo.getArgs()[0]);   
  2. }   
  3.  
  4. }   
  5.  
  6.  
  7. }   

6.實(shí)現(xiàn)動(dòng)態(tài)代理處理器InterceptorHandler

該類(lèi)實(shí)現(xiàn)了java.lang.reflect.InvocationHandler接口。

  1. public class InterceptorHandler implements InvocationHandler {

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

  3. //攔截器列表

  4. private List interceptors = null;

  5. //存放原始對(duì)象

  6. private Object orginalObject;

  7. //使用Proxy返回一個(gè)對(duì)象。注意這里傳進(jìn)去的對(duì)象的對(duì)象必須實(shí)現(xiàn)一個(gè)接口

  8. public Object bind(Object obj) {   
  9.  
  10. this.orginalObject = obj;   
  11.  
  12. return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj   
  13.  
  14. .getClass().getInterfaces(), this);   
  15.  
  16. }   
  17.  
  18.  
  19.  
  20. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   
  21.  
  22. Object result = null;   
  23.  
  24. Throwable ex = null;   
  25.  
  26. InvokeJniInfo invInfo = new InvokeJniInfo(proxy,method,args,result,ex);   
  27.  
  28. log.debug("Invoking Before Intercepors!");   

//實(shí)現(xiàn)方法調(diào)用之前進(jìn)行攔截的方法

  1. invokeInterceptorBefor(invInfo);   
  2.  
  3.  
  4. try{   
  5.  
  6. log.debug("Invoking Proxy Method!");   
  7.  
  8. //調(diào)用方法   
  9.  
  10. result = method.invoke(orginalObject,args);   
  11.  
  12.  
  13. invInfo.setResult(result);   
  14.  
  15. log.debug("Invoking After method!");   

//實(shí)現(xiàn)方法調(diào)用之后進(jìn)行攔截的方法

  1. invokeInterceptorAfter(invInfo);   
  2.  
  3.  
  4. }catch(Throwable tr){   
  5.  
  6. invInfo.setException(tr);   
  7.  
  8. log.error("Invoking exceptionThrow method!");   

//實(shí)現(xiàn)出現(xiàn)異常進(jìn)行攔截的方法

  1. invokeInterceptorExceptionThrow(invInfo);   
  2.  
  3. }   
  4.  
  5. return result;   
  6.  
  7. }   

//獲取攔截器列表

  1. private synchronized List getIntercetors(){   
  2.  
  3. if(null == interceptors){   
  4.  
  5. interceptors = new ArrayList();   

//添加日志記錄攔截器

  1. interceptors.add(new LogInterceptor());  

//添加初始化JavaBean攔截器

  1. interceptors.add(new InitParamsInterceptor());  

//如果需要添加其他功能,可以很方便的添加其他的攔截器實(shí)現(xiàn)功能

  1. }   
  2.  
  3. return interceptors;   
  4.  
  5. }   
  6.  
  7. private void invokeInterceptorBefor(InvokeJniInfo invInfo){   
  8.  
  9. List interceptors = getIntercetors();   
  10.  
  11. int len = interceptors.size();   

//遍歷所有攔截器,并調(diào)用攔截器的before方法

  1. for(int i = 0;i((Interceptor)interceptors.get(i)).before(invInfo);   
  2.  
  3. }   
  4.  
  5. }   
  6.  
  7.  
  8. private void invokeInterceptorAfter(InvokeJniInfo invInfo){   
  9.  
  10. List interceptors = getIntercetors();   
  11.  
  12. int len = interceptors.size();   

//遍歷所有攔截器,并調(diào)用攔截器的after方法

  1. for(int i = len - 1;i >= 0;i--){   
  2.  
  3. ((Interceptor)interceptors.get(i)).after(invInfo);   
  4.  
  5. }   
  6.  
  7. }   
  8.  
  9.  
  10. private void invokeInterceptorExceptionThrow(InvokeJniInfo invInfo){   
  11.  
  12. List interceptors = getIntercetors();   
  13.  
  14. int len = interceptors.size();   

//遍歷所有攔截器,并調(diào)用攔截器的exceptionThrow方法

  1. for(int i = len - 1;i >= 0;i--){   
  2.  
  3. ((Interceptor)interceptors.get(i)).exceptionThrow(invInfo);   
  4.  
  5. }   
  6.  
  7. }   
  8.  
  9. }   

7.獲取動(dòng)態(tài)代理對(duì)象工廠InterceptorFactory

  1. public class InterceptorFactory {   
  2.  
  3. private static Log log = LogFactory.getLog(InterceptorFactory.class);   
  4.  
  5. public static Object getClassInstance(String clzName) {   
  6.  
  7. Class cls;   
  8.  
  9. Object obj = null;   
  10.  
  11. try {   
  12.  
  13. cls = Class.forName(clzName);   
  14.  
  15. obj = (Object) cls.newInstance();   
  16.  
  17. } catch (Exception e) {   
  18.  
  19. log.error(e.getStackTrace());   
  20.  
  21. }   
  22.  
  23. return obj;   
  24.  
  25. }   
  26.  
  27. public static Object getInterceptorProxyedObject(String clzName) {   
  28.  
  29. InterceptorHandler aopHandler = new InterceptorHandler();   
  30.  
  31. Object obj = getClassInstance(clzName);   
  32.  
  33. return aopHandler.bind(obj);   
  34.  
  35. }   
  36.  
  37. }   
  38.  
  39.  
  40. 8.修改以前的代碼,使用動(dòng)態(tài)代理實(shí)現(xiàn)   
  41.  
  42. public class SOAP{   
  43.  
  44. private JniInterface jni = null;   
  45.  
  46. private Log log = 。。。;   
  47.  
  48. public SOAP(){   
  49.  
  50. jni=(JniInterface)InterceptorFactory.getInterceptorProxyedObject("JniClass");   
  51.  
  52. }   
  53.  
  54.  
  55. /**方法A**/   
  56.  
  57. public JavaBeanA aMethod(JavaBeanA javaBeanA){   
  58.  
  59. return jni.aMethod(javaBeanA);   
  60.  
  61. }   

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

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

等等,很多這樣的方法

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

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

}


從紅色代碼對(duì)比可以看出,省了很多代碼。

三、總結(jié)

1.必須徹底貫徹針對(duì)接口編成這一編程思想。

2.明白了這個(gè),是不是也明白了Spring的AOP的實(shí)現(xiàn)了?以及為什么要使用Spring的AOP的時(shí)候必須使用他的BeanFactory呢?

【編輯推薦】

  1. Java連接MySQL中文亂碼處理
  2. 在Java應(yīng)用程序中使用Jfreechart配置
  3. Java虛擬機(jī)內(nèi)部構(gòu)成淺析
  4. 淺談Java線程的生命周期
  5. 關(guān)于Java繼承的一些復(fù)習(xí)
責(zé)任編輯:張燕妮 來(lái)源: 賽迪網(wǎng)
相關(guān)推薦

2022-02-08 17:07:54

Spring BooSpring Aop日志記錄

2023-11-07 16:00:25

面向切面編程開(kāi)發(fā)

2010-04-26 08:53:06

面向方面編程.NET

2021-07-14 11:07:56

AOPJDKCglib

2015-09-28 15:59:00

Java動(dòng)態(tài)代理機(jī)制

2017-05-11 21:30:01

Android動(dòng)態(tài)代理ServiceHook

2015-09-22 11:09:47

Java 8動(dòng)態(tài)代理

2022-09-01 10:40:29

SpringAOPJDK

2023-03-30 07:48:46

接口鑒權(quán)SpringBoot

2021-03-22 08:45:30

異步編程Java

2013-06-14 11:18:41

Fedora Gnu PG 代理

2011-04-06 11:41:25

Java動(dòng)態(tài)代理

2023-03-16 07:52:47

Golang函數(shù)式編程

2012-08-28 10:59:26

JavaJava動(dòng)態(tài)代理Proxy

2025-02-27 00:32:35

2011-12-08 10:24:53

JavaNIO

2017-10-12 14:56:11

2011-03-23 10:40:51

java代理模式

2024-09-05 09:35:58

CGLIBSpring動(dòng)態(tài)代理

2023-12-06 08:23:44

代理模式設(shè)計(jì)模式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)