【本節目标】
本節介紹了靜态代理設計模式的弊端以及解決方案:實作動态代理機制。
靜态代理設計模式
代理設計模式是在程式開發中使用最多的設計模式,代理設計模式的核心是有真實業務實作類和代理業務實作類,并且代理類要完成比真實業務更多的處理操作。
傳統代理設計模式的弊端
所有的代理設計模式如果按照設計要求來說,必須是基于接口的設計,也就是說需要首先定義出核心接口的組成。
範例:模拟一個消息發送的代理操作結構(傳統代理設計)
public class JavaAPIDemo {
public static void main(String[] args)throws Exception{
IMessage message=new MessageProxy(new MessageReal());
message.send();
}
}
interface IMessage{ //傳統代理設計必須有接口
public void send(); //業務方法
}
class MessageReal implements IMessage {
@Override
public void send() {
System.out.println("【發送消息】www.mldn.cn");
}
}
class MessageProxy implements IMessage { //代理類
private IMessage message; //代理對象,一定是業務接口執行個體
public MessageProxy(IMessage message){
this.message=message;
}
@Override
public void send() {
if(this.connect()){
this.message.send(); //消息的發送處理
this.close();
}
}
public boolean connect(){
System.out.println("【消息代理】進行消息發送通道的連接配接。");
return true;
}
public void close(){
System.out.println("【消息代理】關閉消息通道。");
}
}
執行結果:
傳統代理設計
以上的操作代碼是一個最為标準的代理設計,但是如果要進一步的去思考會發現用戶端的接口與具體的子類産生了耦合問題,是以這樣的操作如果從實際的開發來講,最好再引入工廠設計模式進行代理對象的擷取。
以上的代理設計模式為靜态代理設計,這種靜态代理涉及的特點在于:一個代理類隻為一個接口服務,如果現在準備有3000個業務接口,則按照此種做法就意味着需要編寫3000個代理類,并且這些代理類操作形式類似。
是以現在需要解決的問題在于:如何可以讓一個代理類滿足于所有的業務接口操作要求。
動态代理設計模式
通過靜态代理設計模式的缺陷可以發現,最好的做法是為所有功能一緻的業務操作接口提供有統一的代理處理操作,而這就可以通過動态代理機制來實作,但是在動态代理機制中需要考慮到如下幾點問題:
- 不管是動态代理類還是靜态代理類都一定要接收真實業務實作子類對象;
- 由于動态代理類不再與某一個具體的接口進行捆綁,是以應該可以動态擷取類的接口資訊。
在進行動态代理實作的操作中,首先需要關注的就是一個InvocationHandler接口,這個接口規定了代理方法的執行。
public interface InvocationHandler{
/**
* 代理方法調用,代理主體類中執行的方法最終都是此方法
* @param proxy 要代理的對象
* @param method 要執行的接口方法名稱
* @param args 傳遞的參數
* @return 某一個方法的傳回值
* @throws Throwable 方法調用時出現的錯誤繼續向上抛出
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
在進行動态代理設計時,對于動态對象的建立是由JVM底層完成的,此時主要依靠的是java.lang.reflect.Proxy程式類,而這個類中隻提供了一個核心方法:
代理對象:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- ClassLoader loader:擷取目前真實主體類的ClassLoader;
- Class<?>[] interfaces:代理是圍繞接口進行的,是以一定要擷取真實主體類的接口資訊;
- InvocationHandler h:代理處理的方法;
代理方法
範例:實作動态代理機制
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaAPIDemo {
public static void main(String[] args)throws Exception{
IMessage msg=(IMessage)new MLDNProxy().bind(new MessageReal());
msg.send();
}
}
class MLDNProxy implements InvocationHandler{
private Object target; //儲存真實業務對象
/**
* 進行真實業務對象與代理業務對象之間的綁定處理
* @param target 真實業務對象
* @return Proxy生成的代理業務對象
*/
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
public boolean connect(){
System.out.println("【消息代理】進行消息發送通道的連接配接。");
return true;
}
public void close(){
System.out.println("【消息代理】關閉消息通道。");
}
@Override
public Object invoke(Object pro, Method method, Object[] args) throws Throwable {
System.out.println("*****【執行方法: 】"+method);
Object returnData = null;
if(this.connect()){
returnData = method.invoke(this.target, args);
this.close();
}
return returnData;
}
}
interface IMessage{ //傳統代理設計必須有接口
void send(); //業務方法
}
class MessageReal implements IMessage {
@Override
public void send() {
System.out.println("【發送消息】www.mldn.cn");
}
}
如果認真觀察系統中提供的Proxy.newProxyInstance()方法,會發現該方法會使用大量的底層機制來進行代理對象的動态建立,所有的代理類是符合所有相關功能需求的操作功能類,它不再代表具體的接口,這樣在處理時就必須依賴于類加載器與接口進行代理對象的僞造。
想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。
本内容視訊來源于
阿裡雲大學 下一篇:CGLIB實作代理設計模式 | 帶你學《Java語言進階特性》之九十六 更多Java面向對象程式設計文章檢視此處