日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Android動(dòng)態(tài)代理以及利用動(dòng)態(tài)代理實(shí)現(xiàn)ServiceHook

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

首先我們要介紹的就是 Java 動(dòng)態(tài)代理,Java 的動(dòng)態(tài)代理涉及到兩個(gè)類:InvocationHandler 接口和 Proxy 類,下面我們會(huì)著重介紹一下這兩個(gè)類,并且結(jié)合實(shí)例來(lái)著重分析一下使用的正確姿勢(shì)等。在這之前簡(jiǎn)單介紹一下 Java 中 class 文件的生成和加載過(guò)程,Java 編譯器編譯好 Java 文件之后會(huì)在磁盤中產(chǎn)生 .class 文件。這種 .class 文件是二進(jìn)制文件,內(nèi)容是只有 JVM 虛擬機(jī)才能識(shí)別的機(jī)器碼,JVM 虛擬機(jī)讀取字節(jié)碼文件,取出二進(jìn)制數(shù)據(jù),加載到內(nèi)存中,解析 .class 文件內(nèi)的信息,使用相對(duì)應(yīng)的 ClassLoader 類加載器生成對(duì)應(yīng)的 Class 對(duì)象:

.class 字節(jié)碼文件是根據(jù) JVM 虛擬機(jī)規(guī)范中規(guī)定的字節(jié)碼組織規(guī)則生成的,具體的 .class 文件格式介紹可以查看博客 深入理解Java Class文件格式 和 Java 虛擬機(jī)規(guī)范。

通過(guò)上面我們知道 JVM 是通過(guò)字節(jié)碼的二進(jìn)制信息加載類的,那么我們?nèi)绻谶\(yùn)行期系統(tǒng)中,遵循 Java 編譯系統(tǒng)組織 .class 文件的格式和結(jié)構(gòu),生成相應(yīng)的二進(jìn)制數(shù)據(jù),然后再把這個(gè)二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成對(duì)應(yīng)的類,這樣就可以在運(yùn)行中動(dòng)態(tài)生成一個(gè)我們想要的類了:

Java 中有很多的框架可以在運(yùn)行時(shí)根據(jù) JVM 規(guī)范動(dòng)態(tài)的生成對(duì)應(yīng)的 .class 二進(jìn)制字節(jié)碼,比如 ASM 和 Javassist 等,這里就不詳細(xì)介紹了,感興趣的可以去查閱相關(guān)的資料。這里我們就以動(dòng)態(tài)代理模式為例來(lái)介紹一下我們要用到這兩個(gè)很重要的類,關(guān)于動(dòng)態(tài)代理模式,我在 java/android 設(shè)計(jì)模式學(xué)習(xí)筆記(9)—代理模式中已經(jīng)介紹過(guò)了,但是當(dāng)時(shí)并沒(méi)有詳細(xì)分析過(guò) InvocationHandler 接口和 Proxy 類,這里就來(lái)詳細(xì)介紹一下。在代理模式那篇博客中,我們提到了代理模式分為動(dòng)態(tài)代理和靜態(tài)代理:

上面就是靜態(tài)代理模式的類圖,當(dāng)在代碼階段規(guī)定這種代理關(guān)系時(shí),ProxySubject 類通過(guò)編譯器生成 .class 字節(jié)碼文件,當(dāng)系統(tǒng)運(yùn)行之前,這個(gè) .class 文件就已經(jīng)存在了。動(dòng)態(tài)代理模式的結(jié)構(gòu)和上面的靜態(tài)代理模式的結(jié)構(gòu)稍微有所不同,它引入了一個(gè) InvocationHandler 接口和 Proxy 類。在靜態(tài)代理模式中,代理類 ProxySubject 中的方法,都指定地調(diào)用到特定 RealSubject 中對(duì)應(yīng)的方法,ProxySubject 所做的事情無(wú)非是調(diào)用觸發(fā) RealSubject 對(duì)應(yīng)的方法;動(dòng)態(tài)代理工作的基本模式就是將自己方法功能的實(shí)現(xiàn)交給 InvocationHandler 角色,外界對(duì) Proxy 角色中每一個(gè)方法的調(diào)用,Proxy 角色都會(huì)交給 InvocationHandler 來(lái)處理,而 InvocationHandler 則調(diào)用 RealSubject 的方法,如下圖所示:

InvocationHandler 接口和 Proxy 類

我們來(lái)分析一下動(dòng)態(tài)代理模式中 ProxySubject 的生成步驟:

  1. 獲取 RealSubject 上的所有接口列表;
  2. 確定要生成的代理類的類名,系統(tǒng)默認(rèn)生成的名字為:com.sun.proxy.$ProxyXXXX ;
  3. 根據(jù)需要實(shí)現(xiàn)的接口信息,在代碼中動(dòng)態(tài)創(chuàng)建該 ProxySubject 類的字節(jié)碼;
  4. 將對(duì)應(yīng)的字節(jié)碼轉(zhuǎn)換為對(duì)應(yīng)的 Class 對(duì)象;
  5. 創(chuàng)建 InvocationHandler 的實(shí)例對(duì)象 h,用來(lái)處理 Proxy 角色的所有方法調(diào)用;
  6. 以創(chuàng)建的 h 對(duì)象為參數(shù),實(shí)例化一個(gè) Proxy 角色對(duì)象。

具體的代碼為:

Subject.java

 
 
 
 
  1. public interface Subject {
  2.     String operation();

RealSubject.java

 
 
 
 
  1. public class RealSubject implements Subject{
  2.     @Override
  3.     public String operation() {
  4.         return "operation by subject";
  5.     }

ProxySubject.java

 
 
 
 
  1. public class ProxySubject implements InvocationHandler{
  2.      protected Subject subject;
  3.     public ProxySubject(Subject subject) {
  4.         this.subject = subject;
  5.     }
  6.     @Override
  7.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  8.         //do something before
  9.         return method.invoke(subject, args);
  10.     }

測(cè)試代碼

 
 
 
 
  1. Subject subject = new RealSubject();
  2. ProxySubject proxy = new ProxySubject(subject);
  3. Subject sub = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
  4.         subject.getClass().getInterfaces(), proxy);
  5. sub.operation(); 

以上就是動(dòng)態(tài)代理模式的最簡(jiǎn)單實(shí)現(xiàn)代碼,JDK 通過(guò)使用 java.lang.reflect.Proxy 包來(lái)支持動(dòng)態(tài)代理,我們來(lái)看看這個(gè)類的表述:

 
 
 
 
  1. Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the 
  2. superclass of all dynamic proxy classes created by those methods. 

一般情況下,我們使用下面的

 
 
 
 
  1. public static Object newProxyInstance(ClassLoader loader, Class[]interfaces,InvocationHandler h) throws IllegalArgumentException { 
  2.     // 檢查 h 不為空,否則拋異常
  3.     if (h == null) { 
  4.         throw new NullPointerException(); 
  5.     } 
  6.     // 獲得與指定類裝載器和一組接口相關(guān)的代理類類型對(duì)象
  7.     Class cl = getProxyClass(loader, interfaces); 
  8.     // 通過(guò)反射獲取構(gòu)造函數(shù)對(duì)象并生成代理類實(shí)例
  9.     try { 
  10.         Constructor cons = cl.getConstructor(constructorParams); 
  11.         return (Object) cons.newInstance(new Object[] { h }); 
  12.     } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); 
  13.     } catch (IllegalAccessException e) { throw new InternalError(e.toString()); 
  14.     } catch (InstantiationException e) { throw new InternalError(e.toString()); 
  15.     } catch (InvocationTargetException e) { throw new InternalError(e.toString()); 
  16.     } 

Proxy 類的 getProxyClass 方法調(diào)用了 ProxyGenerator 的 generatorProxyClass 方法去生成動(dòng)態(tài)類:

 
 
 
 
  1. public static byte[] generateProxyClass(final String name, Class[] interfaces)

這個(gè)方法我們下面將會(huì)介紹到,這里先略過(guò),生成這個(gè)動(dòng)態(tài)類的字節(jié)碼之后,通過(guò)反射去生成這個(gè)動(dòng)態(tài)類的對(duì)象,通過(guò) Proxy 類的這個(gè)靜態(tài)函數(shù)生成了一個(gè)動(dòng)態(tài)代理對(duì)象 sub 之后,調(diào)用 sub 代理對(duì)象的每一個(gè)方法,在代碼內(nèi)部,都是直接調(diào)用了 InvocationHandler 的 invoke 方法,而 invoke 方法根據(jù)代理類傳遞給自己的 method 參數(shù)來(lái)區(qū)分是什么方法,我們來(lái)看看 InvocationHandler 類的介紹:

 
 
 
 
  1. InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
  2. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy 
  3. instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler. 
Public methods  
abstract Object invoke(Object proxy, Method method, Object[] args)Processes a method invocation on a proxy instance and returns the result.

方法的參數(shù)和返回:

Parameters  
proxy Object: the proxy instance that the method was invoked on
method Method: the Method instance corresponding to the interface method invoked on the proxy instance. The declaring class of the Method object will be the interface that the method was declared in, which may be a superinterface of the proxy interface that the proxy class inherits the method through.
args Object: an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or null if interface method takes no arguments. Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper class, such as java.lang.Integer or java.lang.Boolean.
Returns  
Object the value to return from the method invocation on the proxy instance. If the declared return type of the interface method is a primitive type, then the value returned by this method must be an instance of the corresponding primitive wrapper class; otherwise, it must be a type assignable to the declared return type. If the value returned by this method is null and the interface method’s return type is primitive, then a NullPointerException will be thrown by the method invocation on the proxy instance. If the value returned by this method is otherwise not compatible with the interface method’s declared return type as described above, a ClassCastException will be thrown by the method invocation on the proxy instance.

上面提到的一點(diǎn)需要特別注意的是,如果 Subject 類中定義的方法返回值為 8 種基本數(shù)據(jù)類型,那么在 ProxySubject 類中必須要返回相應(yīng)的基本類型包裝類,即 int 對(duì)應(yīng)的返回為 Integer 等等,還需要注意的是如果此時(shí)返回 null,則會(huì)拋出 NullPointerException,除此之外的其他情況下返回值的對(duì)象必須要和 Subject 類中定義方法的返回值一致,要不然會(huì)拋出 ClassCastException。

生成源碼分析

那么通過(guò) Proxy 類的 newProxyInstance 方法動(dòng)態(tài)生成的類是什么樣子的呢,我們上面也提到了,JDK 為我們提供了一個(gè)方法 ProxyGenerator.generateProxyClass(String proxyName,class[] interfaces) 來(lái)產(chǎn)生動(dòng)態(tài)代理類的字節(jié)碼,這個(gè)類位于 sun.misc 包中,是屬于特殊的 jar 包,于是問(wèn)題又來(lái)了,Android studio 創(chuàng)建的 android 工程是沒(méi)法找到 ProxyGenerator 這個(gè)類的,這個(gè)類在 jre 目錄下,就算我把這個(gè)類相關(guān)的 .jar 包拷貝到工程里面并且在 gradle 里面引用它,雖然最后能夠找到這個(gè)類,但是編譯時(shí)又會(huì)出現(xiàn)很奇葩的問(wèn)題,所以,沒(méi)辦法嘍,android studio 沒(méi)辦法創(chuàng)建普通的 java 工程,只能自己裝一個(gè) intellij idea 或者求助相關(guān)的同事了。創(chuàng)建好 java 工程之后,使用下面這段代碼就可以將生成的類導(dǎo)出到指定路徑下面:

  1. public static void generateClassFile(Class clazz,String proxyName)
  2. {
  3.     //根據(jù)類信息和提供的代理類名稱,生成字節(jié)碼  
  4.     byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
  5.     String paths = "D:\\"; // 這里寫死路徑為 D 盤,可以根據(jù)實(shí)際需要去修改&n

    網(wǎng)頁(yè)題目:Android動(dòng)態(tài)代理以及利用動(dòng)態(tài)代理實(shí)現(xiàn)ServiceHook
    文章出自:http://www.5511xx.com/article/cojooed.html