【Java基礎】代理 - Proxy
利用代理可以在執行時建立一個實現了一組給定介面的新類。這種功能只有在編譯時無法確定需要實現哪個介面時才有必要使用。
代理類是在程式執行過程中建立的。然而,一旦被建立,就變成了常規類,與虛擬機器中的任何其他類沒有什麼區別。
對於特定的類載入器和預設的一組介面來說,只能有一個代理類。也就是說,如果使用同一個類載入器和介面陣列呼叫兩次newProxyInstance方法的話,只能夠得到同一個類的兩個物件。
代理實際上就是java.lang.reflect.Proxy動態地根據所指定的介面生成的class byte。該類會繼承Proxy類,並實現所有指定的介面(interfaces引數),最後使用參入的class loader將class byte載入如系統,生成這樣的一個類的物件。
在最後的一個示例中,可以看到生成的代理類的繼承體系及實現的介面。
代理類 - Proxy
public class Proxy extends Object implements Serializable (java.lang.reflect)
要想建立一個代理物件,需要使用Proxy類的newProxyInstance方法,這個方法有三個引數:
static Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.
|
- 一個類載入器:作為Java安全模型的一部分,對於系統類和從因特網上下載來的類,可以使用不同的類載入器。使用null表示使用預設的類載入器(系統類的載入器)。
- 一個Class物件陣列,每個元素都是需要實現的介面。
- 一個呼叫處理器。
呼叫處理器 - InvocationHandler
public interface InvocationHandler (java.lang.reflect)
Modifier and Type | Method and Description |
---|---|
Object |
invoke(Object proxy, Method method, Object[] args)
Processes a method invocation on a proxy instance and returns the result.
|
當呼叫代理類時,代理類只會呼叫InvocationHandler的invoke方法,所以真正實現的方法必須在invoke方法中去呼叫。
示例
系統介面代理
Integer類實現了Comparable介面。
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest {
public static void main(String[] args){
Object[] elements = new Object[100];
// fill elements with proxies for the integer
for (int i = 0; i < elements.length; i++){
Integer value = i + 1;
Class[] interfaces = value.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
elements[i] = proxy;
}
// construct a random integer
Integer key = new Random().nextInt(elements.length) + 1;
// search for the key
int result = Arrays.binarySearch(elements, key);
if (result >= 0){
System.out.println(elements[result]);
}
}
}
class TraceHandler implements InvocationHandler{
private Object target;
public TraceHandler(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
自定義介面代理
import java.util.*;
import java.lang.reflect.*;
public class ProxyTest2 {
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
((TestInterface)proxy).test();
//((TestClass)proxy).test(); error; Proxy cannot be cast to TestClass
//((TestClass)proxy).test2(); error; Proxy cannot be cast to TestClass
}
}
interface TestInterface{
void test();
}
class TestClass implements TestInterface{
public void test(){
System.out.println("TestClass.test");
}
public void test2(){
System.out.println("TestClass.test2");
}
public String toString(){
return "TestClass Instance";
}
}
class TraceHandler2 implements InvocationHandler{
private Object target;
public TraceHandler2(Object t){
target = t;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
// print the invoked method info
System.out.print("Proxy invoke: ");
System.out.print(target);
System.out.print("." + m.getName() + "(");
if (args != null){
for (int i = 0; i < args.length; i++){
System.out.print(args[i]);
if (i < args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
// invoke actual method
return m.invoke(target, args);
}
}
列印代理類
我們使用反射中的列印類資訊的方法,檢視上面示例中生成的代理類的定義:
public class ReflectionTest{
public static void main(String[] args){
TestClass testClass = new TestClass();
Class[] interfaces = testClass.getClass().getInterfaces();
InvocationHandler handler = new TraceHandler2(testClass);
Object proxy = Proxy.newProxyInstance(testClass.getClass().getClassLoader(), interfaces, handler);
ClassAnalyzer.printClass(proxy.getClass());
}
}
輸出:
相關文章
- Java基礎之代理模式Java模式
- Java中的代理模式(Proxy Pattern)Java模式
- Java代理機制分析——JDK代理(Proxy、InvocationHandler與示例)JavaJDK
- Java基礎系列-靜態代理和動態代理Java
- java動態代理——欄位和方法位元組碼的基礎結構及Proxy原始碼分析三Java原始碼
- 代理模式(Proxy)模式
- java23中設計模式–代理模式ProxyJava設計模式
- java23中設計模式--代理模式ProxyJava設計模式
- JAVA-Spring AOP基礎 - 代理設計模式JavaSpring設計模式
- java基礎:深入理解JDK動態代理JavaJDK
- 代理模式(Proxy Pattern)模式
- 代理(Proxy)的解析
- Java JDK Proxy和CGLib動態代理示例講解JavaJDKCGLib
- Java進階 | Proxy動態代理機制詳解Java
- Java代理設計模式(Proxy)的四種具體實現:靜態代理和動態代理Java設計模式
- go proxy 實現反向代理Go
- JS 基礎篇(代理模式)JS模式
- java動態代理——代理方法的假設和驗證及Proxy原始碼分析五Java原始碼
- VUE 未來代理操作:ES6 Proxy代理Vue
- java動態代理基本原理及proxy原始碼分析一Java原始碼
- Java提高班(六)反射和動態代理(JDK Proxy和Cglib)Java反射JDKCGLib
- Nginx proxy manager反向代理docker hubNginxDocker
- Proxy代理資料攔截方法
- Java基礎-語法基礎Java
- 技術分享:Proxy-Pool代理池搭建IP代理
- java基礎Java
- [Java基礎]Java
- JAVA 基礎Java
- Java 基礎02Java程式設計基礎Java程式設計
- Java基礎-物件導向基礎Java物件
- AndroidStudio清除重置Http Proxy代理的方式AndroidHTTP
- 部署一臺Zabbix Proxy代理服務
- Nginx代理緩衝 proxy_buffering 配置Nginx
- 設計模式之代理模式(proxy pattern)設計模式
- 前端 | Nuxt.js axios baseURL,proxy 代理前端UXJSiOS
- nginx的反向代理proxy_pass指令Nginx
- iOS 設定代理(Proxy)方案總結iOS
- Java基礎 —— 反射Java反射
- [Java基礎]IOJava