1. 程式人生 > 實用技巧 >Java 代理設計模式

Java 代理設計模式

Java 代理設計模式

為其他物件提供一種代理以控制對這個物件的訪問。代理物件起到中介作用,可去掉功能服務或增加額外的服務

1、靜態代理

在靜態代理模式之下,我們顯示地建立代理類,代理類持有被代理類的物件,實現與被代理類 的相同介面,並且增添相應的業務邏輯,以達到代理的效果

代理和被代理物件在代理之前是確定的,他們都實現相同的介面或者繼承相同的抽象類

如何實現:建立一個介面,然後建立被代理的類實現該介面並且實現該介面中的抽象方法。之後再建立一個代理類,同時使其也實現這個介面。在代理類中持有一個被代理物件的引用,而後在代理類方法中呼叫該物件的方法

/**
* 服務介面
*/
public interface Service {

/**
* 服務
*/
void doService(String name);

}

/**
* 服務員
*/
public class Waiter implements Service{

@Override
public void doService(String name) {
System.out.println("正在服務"+name);
}
}

/**
* 代理服務員
*/
public class ProxyWaiter implements Service{
private Waiter waiter;//目標物件

public ProxyWaiter(Waiter waiter) {
this.waiter = waiter;
}

/**
* 服務
* @param name
*/
@Override
public void doService(String name) {
System.out.println("歡迎光臨");
waiter.doService(name);
System.out.println("歡迎下次光臨");
}
}

/**
*測試類
*/
public class Test {

public static void main(String[] args) {
//服務員(目標物件)
Waiter waiter=new Waiter();
//代理物件
ProxyWaiter proxyWaiter=new ProxyWaiter(waiter);
//服務
proxyWaiter.doService("lsy");
}

}

2、動態代理(重點)

2.1、jdk動態代理

利用反射機制在執行時建立代理類,代理物件必須實現某個介面

jdk動態代理具體步驟:

  • 通過實現 InvocationHandler 介面建立自己的呼叫處理器;

  • 通過為 Proxy 類指定 ClassLoader 物件和一組 interface 來建立動態代理類;

  • 通過反射機制獲得動態代理類的建構函式,其唯一引數型別是呼叫處理器介面型別;

  • 通過建構函式建立動態代理類例項,構造時呼叫處理器物件作為引數被傳入。

/**
* 服務介面
*/
public interface Service {

/**
* 服務
*/
void doService(String name);

}

/**
* 服務員
*/
public class Waiter implements Service {

/**
* 服務
* @param name
*/
@Override
public void doService(String name) {
System.out.println("正在服務"+name);
}
}

/**
* 處理目標物件類,實現InvocationHandler介面
*/
public class ProxyHandler implements InvocationHandler {
private Object object;//目標物件(必須要實現一個介面)

public ProxyHandler(Object object) {
this.object = object;
}

/**
* 處理主體:編寫代理的邏輯程式碼增強
* 引數一: proxy: 代理的物件
* 引數二: method:代理類物件呼叫的方法
* 引數三: args: 代理類方法的引數
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("歡迎光臨");
method.invoke(object,args);
System.out.println("歡迎下次光臨");
return null;
}
}

/**
*測試類
*/
public class Test {

public static void main(String[] args) {
//服務員(目標物件)
Waiter waiter=new Waiter();
//代理目標物件
ProxyHandler proxyHandler=new ProxyHandler(waiter);
//得到代理後的目標物件(不能強轉為介面的實現)
Service service= (Service) Proxy.newProxyInstance(waiter.getClass().getClassLoader(),waiter.getClass().getInterfaces(),proxyHandler);
//服務
service.doService("lsy");
}

}

參考資料:https://www.jianshu.com/p/9bcac608c714

2.2、cglib動態代理

通過cglib的動態代理它能夠針對實現沒有介面的目標類,進行動態代理

注意:要手動載入cglib的庫檔案

  • 實現原理

    • cglib它會生成目標類的子類實現,因此目標類作為父類注入,並且呼叫父類的方法

/**
* 服務員(目標物件)
*/
public class Waiter {

/**
* 服務
*/
public void doService(){
System.out.println("正在服務");
}

}

/**
* 代理目標物件類
*/
public class MyMethodInterceptor implements MethodInterceptor {

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("準備服務");
//呼叫目標物件的方法
Object object=methodProxy.invokeSuper(o,objects);
System.out.println("服務結束");
return object;
}
}

/**
* 測試類
*/
public class Test {

public static void main(String[] args) {
//目標物件
Waiter waiter=new Waiter();
//建立Enhancer物件,類似於JDK動態代理的Proxy類,下一步就是設定幾個引數
Enhancer enhancer = new Enhancer();
//注入目標物件類位元組碼檔案
enhancer.setSuperclass(Waiter.class);
//設定回撥函式
enhancer.setCallback(new MyMethodInterceptor());
//獲取代理後的目標物件
Waiter w=(Waiter) enhancer.create();
//服務
w.doService();
}

}

參考資料:https://www.cnblogs.com/wyq1995/p/10945034.html