Java Proxy機(jī)制詳細(xì)解讀
動(dòng)態(tài)代理其實(shí)就是java.lang.reflect.Proxy類(lèi)動(dòng)態(tài)的根據(jù)您指定的所有接口生成一個(gè)class byte,該class會(huì)繼承Proxy類(lèi),并實(shí)現(xiàn)所有你指定的接口(您在參數(shù)中傳入的接口數(shù)組);然后再利用您指定的classloader將 class byte加載進(jìn)系統(tǒng),最后生成這樣一個(gè)類(lèi)的對(duì)象,并初始化該對(duì)象的一些值,如invocationHandler,以即所有的接口對(duì)應(yīng)的Method成員。 初始化之后將對(duì)象返回給調(diào)用的客戶(hù)端。這樣客戶(hù)端拿到的就是一個(gè)實(shí)現(xiàn)你所有的接口的Proxy對(duì)象。請(qǐng)看實(shí)例分析:
一 業(yè)務(wù)接口類(lèi)
public interface BusinessProcessor {
public void processBusiness();
}
二 業(yè)務(wù)實(shí)現(xiàn)類(lèi)
public class BusinessProcessorImpl implements BusinessProcessor {
public void processBusiness() {
System.out.println("processing business.....");
}
}
三 業(yè)務(wù)代理類(lèi)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BusinessProcessorHandler implements InvocationHandler {
private Object target = null;
BusinessProcessorHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("You can do something here before process your business");
Object result = method.invoke(target, args);
System.out.println("You can do something here after process your business");
return result;
}
}
四 客戶(hù)端應(yīng)用類(lèi)
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
bp.processBusiness();
}
}
現(xiàn)在我們看一下打印結(jié)果:
You can do something here before process your business processing business..... You can do something here after process your business
通過(guò)結(jié)果我們就能夠很簡(jiǎn)單的看出Proxy的作用了,它能夠在你的核心業(yè)務(wù)方法前后做一些你所想做的輔助工作,如log日志,安全機(jī)制等等。
現(xiàn)在我們來(lái)分析一下上面的類(lèi)的工作原理。
類(lèi)一二沒(méi)什么好說(shuō)的。先看看類(lèi)三吧。 實(shí)現(xiàn)了InvocationHandler接口的invoke方法。其實(shí)這個(gè)類(lèi)就是最終Proxy調(diào)用的固定接口方法。Proxy不管客戶(hù)端的業(yè)務(wù)方法是怎么實(shí)現(xiàn)的。當(dāng)客戶(hù)端調(diào)用Proxy時(shí),它只會(huì)調(diào)用InvocationHandler的invoke接口,所以我們的真正實(shí)現(xiàn)的方法就必須在invoke方法中去調(diào)用。關(guān)系如下:
BusinessProcessorImpl bpimpl = new BusinessProcessorImpl(); BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl); BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....); bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();
那么bp到底是怎么樣一個(gè)對(duì)象呢。我們改一下main方法看一下就知道了:
public static void main(String[] args) {
BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
bp.processBusiness();
System.out.println(bp.getClass().getName());
}
輸出結(jié)果:
You can do something here before process your business processing business..... You can do something here after process your business $Proxy0
bp原來(lái)是個(gè)$Proxy0這個(gè)類(lèi)的對(duì)象。那么這個(gè)類(lèi)到底是長(zhǎng)什么樣子呢?好的。我們?cè)賹?xiě)二個(gè)方法去把這個(gè)類(lèi)打印出來(lái)看個(gè)究竟,是什么三頭六臂呢?我們?cè)趍ain下面寫(xiě)如下兩個(gè)靜態(tài)方法。
public static String getModifier(int modifier){
String result = "";
switch(modifier){
case Modifier.PRIVATE:
result = "private";
case Modifier.PUBLIC:
result = "public";
case Modifier.PROTECTED:
result = "protected";
case Modifier.ABSTRACT :
result = "abstract";
case Modifier.FINAL :
result = "final";
case Modifier.NATIVE :
result = "native";
case Modifier.STATIC :
result = "static";
case Modifier.SYNCHRONIZED :
result = "synchronized";
case Modifier.STRICT :
result = "strict";
case Modifier.TRANSIENT :
result = "transient";
case Modifier.VOLATILE :
result = "volatile";
case Modifier.INTERFACE :
result = "interface";
}
return result;
}
public static void printClassDefinition(Class clz){
String clzModifier = getModifier(clz.getModifiers());
if(clzModifier!=null && !clzModifier.equals("")){
clzModifier = clzModifier + " ";
}
String superClz = clz.getSuperclass().getName();
if(superClz!=null && !superClz.equals("")){
superClz = "extends " + superClz;
}
Class[] interfaces = clz.getInterfaces();
String inters = "";
for(int i=0; i<interfaces.length; i++){
if(i==0){
inters += "implements ";
}
inters += interfaces[i].getName();
}
System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
System.out.println("{");
Field[] fields = clz.getDeclaredFields();
for(int i=0; i<fields.length; i++){
String modifier = getModifier(fields[i].getModifiers());
if(modifier!=null && !modifier.equals("")){
modifier = modifier + " ";
}
String fieldName = fields[i].getName();
String fieldType = fields[i].getType().getName();
System.out.println(" "+modifier + fieldType + " "+ fieldName + ";");
}
System.out.println();
Method[] methods = clz.getDeclaredMethods();
for(int i=0; i<methods.length; i++){
Method method = methods[i];
String modifier = getModifier(method.getModifiers());
if(modifier!=null && !modifier.equals("")){
modifier = modifier + " ";
}
String methodName = method.getName();
Class returnClz = method.getReturnType();
String retrunType = returnClz.getName();
Class[] clzs = method.getParameterTypes();
String paraList = "(";
for(int j=0; j<clzs.length; j++){
paraList += clzs[j].getName();
if(j != clzs.length -1 ){
paraList += ", ";
}
}
paraList += ")";
clzs = method.getExceptionTypes();
String exceptions = "";
for(int j=0; j<clzs.length; j++){
if(j==0){
exceptions += "throws ";
}
exceptions += clzs[j].getName();
if(j != clzs.length -1 ){
exceptions += ", ";
}
}
exceptions += ";";
String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
System.out.println(" "+methodPrototype );
}
System.out.println("}");
}
再改寫(xiě)main方法
public static void main(String[] args) {
BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
bp.processBusiness();
System.out.println(bp.getClass().getName());
Class clz = bp.getClass();
printClassDefinition(clz);
}
現(xiàn)在我們?cè)倏纯摧敵鼋Y(jié)果:
You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0
$Proxy0 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
java.lang.reflect.Method m4;
java.lang.reflect.Method m2;
java.lang.reflect.Method m0;
java.lang.reflect.Method m3;
java.lang.reflect.Method m1;
void processBusiness();
int hashCode();
boolean equals(java.lang.Object);
java.lang.String toString();
}
很明顯,Proxy.newProxyInstance方法會(huì)做如下幾件事:
1,根據(jù)傳入的第二個(gè)參數(shù)interfaces動(dòng)態(tài)生成一個(gè)類(lèi),實(shí)現(xiàn)interfaces中的接口,該例中即BusinessProcessor接口的processBusiness方法。并且繼承了Proxy類(lèi),重寫(xiě)了hashcode,toString,equals等三個(gè)方法。具體實(shí)現(xiàn)可參看 ProxyGenerator.generateProxyClass(...); 該例中生成了$Proxy0類(lèi)
2,通過(guò)傳入的第一個(gè)參數(shù)classloder將剛生成的類(lèi)加載到j(luò)vm中。即將$Proxy0類(lèi)load
3,利用第三個(gè)參數(shù),調(diào)用$Proxy0的$Proxy0(InvocationHandler)構(gòu)造函數(shù) 創(chuàng)建$Proxy0的對(duì)象,并且用interfaces參數(shù)遍歷其所有接口的方法,并生成Method對(duì)象初始化對(duì)象的幾個(gè)Method成員變量
4,將$Proxy0的實(shí)例返回給客戶(hù)端。
現(xiàn)在好了。我們?cè)倏纯蛻?hù)端怎么調(diào)就清楚了。
1,客戶(hù)端拿到的是$Proxy0的實(shí)例對(duì)象,由于$Proxy0繼承了BusinessProcessor,因此轉(zhuǎn)化為BusinessProcessor沒(méi)任何問(wèn)題。
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
2,bp.processBusiness();
實(shí)際上調(diào)用的是$Proxy0.processBusiness();那么$Proxy0.processBusiness()的實(shí)現(xiàn)就是通過(guò)InvocationHandler去調(diào)用invoke方法啦!
總結(jié)
以上就是本文關(guān)于Java Proxy機(jī)制詳細(xì)解讀的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以參閱:詳解java中的互斥鎖信號(hào)量和多線(xiàn)程等待機(jī)制、關(guān)于Java反射機(jī)制 你需要知道的事情、Java的RTTI和反射機(jī)制代碼分析等,有什么問(wèn)題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家。
相關(guān)文章
MyEclipse如何將項(xiàng)目的開(kāi)發(fā)環(huán)境與服務(wù)器的JDK 版本保持一致
我們使用MyEclipse開(kāi)發(fā)Java項(xiàng)目開(kāi)發(fā)中,偶爾會(huì)遇到因項(xiàng)目開(kāi)發(fā)環(huán)境不協(xié)調(diào),導(dǎo)致這樣那樣的問(wèn)題,在這里以把所有環(huán)境調(diào)整為JDK1.6 為例,給大家詳細(xì)介紹MyEclipse如何將項(xiàng)目的開(kāi)發(fā)環(huán)境與服務(wù)器的JDK 版本保持一致,需要的朋友參考下吧2024-04-04
Java的MyBatis框架中對(duì)數(shù)據(jù)庫(kù)進(jìn)行動(dòng)態(tài)SQL查詢(xún)的教程
這篇文章主要介紹了Java的MyBatis框架中對(duì)數(shù)據(jù)庫(kù)進(jìn)行動(dòng)態(tài)SQL查詢(xún)的教程,講解了MyBatis中一些控制查詢(xún)流程的常用語(yǔ)句,需要的朋友可以參考下2016-04-04
SpringBoot項(xiàng)目更換項(xiàng)目名稱(chēng)的實(shí)現(xiàn)
本文主要介紹了SpringBoot項(xiàng)目更換項(xiàng)目名稱(chēng),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06
Java實(shí)現(xiàn)獲取圖片和視頻文件的Exif信息
這篇文章將重點(diǎn)為大家介紹一下如何使用Java編程語(yǔ)言結(jié)合metadata-extractor去自動(dòng)獲取全景圖片的Exif信息,獲取照片的拍攝坐標(biāo)信息,感興趣的可以了解一下2022-11-11
Spring Security 自動(dòng)踢掉前一個(gè)登錄用戶(hù)的實(shí)現(xiàn)代碼
這篇文章主要介紹了Spring Security 自動(dòng)踢掉前一個(gè)登錄用戶(hù)的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目
本篇文章主要介紹了Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目 ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10

