一、靜態代理
實現代碼:
(1)自定義接口HttpRequest
package com.it.test.proxy;
/**
* http 請求的接口
*/
public interface HttpRequest {
void get();
void post();
}
(2)創建實現類Retrofit、Vally。並實現HttpRequest接口
package com.it.test.proxy;
public class Retrofit implements HttpRequest {
@Override
public void get() {
System.out.println("Retrofit get");
}
@Override
public void post() {
System.out.println("Retrofit post");
}
}
package com.it.test.proxy;
public class Vally implements HttpRequest {
@Override
public void get() {
System.out.println("Vally get");
}
@Override
public void post() {
System.out.println("Vally post");
}
}
(3)創建代理類Agent,並實現HttpRequest接口,在代理類的構造方法中接受實際類,並在實現方法中通過實現類去調用。
/**
* 代理類
*/
public class Agent implements HttpRequest {
private HttpRequest request;
public Agent(HttpRequest request) {
this.request = request;
}
@Override
public void get() {
request.get();
}
@Override
public void post() {
request.post();
}
}
(4)測試
package com.it.test.proxy;
public class Http {
public static void main(String[] args) {
HttpRequest httpRequest = new Agent(new Retrofit());
httpRequest.get();
httpRequest.post();
HttpRequest httpRequest2 = new Agent(new Vally());
httpRequest2.get();
httpRequest2.post();
}
}
在實現中,我們只需要創建代理類,並傳入具體的實際類。通過調用代理類的方法,其實內部完成實際類的調用。代理類,相當做了一層隔離。假如哪一天我們的實際類修改了,換成了別的。我們只需要修改傳入相應的實際類即可。
缺點:當哪一天我們的實際類實現了多個接口,增加了方法,這樣一來,代理類就沒法代理。因爲代理類的構造方法中只接受了一種類型。
二、動態代理
我們知道代理設計模式包含了三個對象
- 代理接口
- 代理類
- 被代理的類
被代理的類和代理類都實現了代理接口。在靜態代理中,代理類只能代理實現一個接口的類,所以當被代理類實現多個接口的時候,無法被代理,因此出現了動態代理。動態代理可以代理多個接口。
1、動態代理使用方法
(1)創建代理接口IWash、IMessage
package com.example.lib;
public interface IWash {
void wash(String msg);
}
package com.example.lib;
public interface IMessage {
void outMessage();
}
(2)創建被代理類,實現IWash和IMessage接口
package com.example.lib;
public class Luxi implements IMessage,IWash {
@Override
public void outMessage() {
System.out.println("Luxi outMessage");
}
@Override
public void wash(String msg) {
System.out.println("Luxi wash"+msg);
}
}
(3)通過Proxy.newProxyInstance創建代理對象
/**
*動態代理
* Object o 代理對象
*
* luxi 被代理對象
*
*/
final Luxi luxi = new Luxi();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
/**
* 創建代理對象
* Object o
* newProxyInstance 方法會在底層生成一個代理類.class到內存中,
* 而在代理類的構造方法中接受了一個InvocationHandler handler。
* 我們傳入匿名內部類,實現其invoke方法,
* 當我們通過代理對象調用代理接口方法的時候
* 在代理類裏會通過傳入的handler調用invoke方法,並傳入 三個參數
* (1)Object o 代理對象
* (2)Method method 通過反射 獲取到的接口的方法,也就是代理類調用接口的方法。
* (3)Object[] objects 方法的參數
* 接着就會回調我們實現的invoke方法
* 在invoke方法中通過反射 使用method 對象執行方法,傳入我們被代理的類對象執行方法,其中還包含了方法的參數
*
*
*
*/
Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
/**
* 這個地方代理對象o之所以可以強轉成IMessage,
* 又可以強轉成IWash
* 是因爲代理類可以實現多個接口,
* 所以可以強轉成任意接口類型
*
*
*/
IMessage msg = (IMessage) o;
msg.outMessage();
IWash wash = (IWash) o;
wash.wash(" hello world");
// proxy();
}
通過代理對象調用outMessage和wash方法, 最終執行了被代理對象 Luxi的outMessage和wash方法
Luxi outMessage
Luxi wash hello world
2、動態代理原理分析
(1)創建動態代理對象,傳入InvocationHandler handler
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
Object o = Proxy.newProxyInstance(MyClass.class.getClassLoader(), new Class[]{IMessage.class,IWash.class},handler );
我們通過Proxy.newProxyInstance方法傳入classLoader,代理接口的class數組、和InvocationHandler handler創建了一個代理對象。
我們知道創建對象肯定需要類,那麼此時我們需要創建一個代理類,才能實例化代理對象。因此在底層實現中首先會創建一個代理的類的class,也就是編譯之後的class文件。寫入到了內存。底層通過調用ProxyGenerator的generateProxyClass方法實現。爲了分析動態代理的原理,我們手動創建一個代理類。
/**
* 生成代理類
*/
private static void proxy(){
String name = IMessage.class.getName()+"$Proxy";
//生成代理類 的Class數據
byte [] bytes = ProxyGenerator.generateProxyClass(name,new Class[]{IMessage.class,IWash.class});
try {
FileOutputStream outputStream =new FileOutputStream("lib/"+name+".class");
outputStream.write(bytes);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
下面是我們生成的代理類IMessage$Proxy
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.example.lib;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class IMessage$Proxy extends Proxy implements IMessage, IWash {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public IMessage$Proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void outMessage() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
也就是當我們調用 Object o = Proxy.newProxyInstance創建代理對象的時候,會先在內存中創建一個IMessageProxy的構造方法中接受了一個InvocationHandler 類型的參數,也就是我們傳入的InvocationHandler handler ,你們內部類對象。實現了invoke方法。
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
當通過代理對象調用裏面的wash方法的時候,就會調用super.h.invoke方法。
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
而h又是父類的成員,接受的正式我們傳入的InvocationHandler 。
protected Proxy(InvocationHandler var1) {
Objects.requireNonNull(var1);
this.h = var1;
}
因此最終調用了我們內部類實現的invoke方法
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
也就是創建代理對象,通過代理對象調用代理接口的方法最終會調用到了我們內部類的invoke方法,
invoke方法有三個參數,我們可以在源碼中看到。
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.lib.IMessage").getMethod("outMessage");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
public final void wash(String var1) throws {
try {
super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
- Object o對象指的是當前的代理對象
- Method method就是源碼中的
m4 = Class.forName("com.example.lib.IWash").getMethod("wash", Class.forName("java.lang.String"));
就是通過反射獲取代理接口中的方法,封裝成Method。
- Object[] objects就是new Object[]{var1},通過代理對象調用方法的時候,我們方法傳入的參數,封裝成了一個數組。
最後在invoke方法中,我們拿到以上的Method對象和參數數組Object[] objects,我們可以通過調用 method.invoke(luxi,objects);方法,從而達到調用了被代理對象Luxi luxi中的方法。因爲代理類和被代理都實現了同一個接口,因此代理類調用的方法,最終反射獲取到該方法,再讓被代理類調用完成最終的實現。
final Luxi luxi = new Luxi();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(luxi,objects);
}
};
小結
- 動態代理可以代理多個接口,靜態代理只能代理一個接口
- 動態代理類不是通過我們手動生成,而是通過ProxyGenerator.generateProxyClass動態生成的一個class。
- 動態代理類創建代理對象的時候需要傳入InvocationHandler 對象,而InvocationHandler 對象是一個接口,因此我們需要手動實現其中invoke方法,invoke方法包含了三個參數,當前代理類對象,Method對象(封裝了要代理的方法),Object[]參數數組(封裝了代理方法的參數值)
- 當我們創建代理對象之後,調用了代理方法,接着在代理類的內部調用了invoke方法,接着回調到了我們實現的invoke方法
- 在invoke方法中我們可以拿到代理的方法和參數,通過反射中method.invoke方法,傳入被代理的對象。最終調用了代理對象的方法