Java代理設計模式(Proxy)的幾種具體實現
Proxy是一種結構設計模型,主要解決物件直接訪問帶來的問題,代理又分為靜態代理和動態代理(JDK代理、CGLIB代理。靜態代理:又程式建立的代理類,或者特定的工具類,在平時開發中經常用到這種代理模式,這種一般在程式執行前就已經生成對應的class檔案;動態代理:在程式執行時通過反射機制動態建立。
下面通過一個場景實現以下三種代理方式
- 步驟一:定義商店介面(Subject)
- 步驟二:個人店家運營(RealSubject)
- 步驟三:平臺運營(proxy)
- 步驟四:個體消費(client)
幾種代理方式都會用到Subject、RealSubject,現在這裡定義Store.java(Subject):定義兩個介面operate(運營),business(交易)。
public interface Store {
/**
* 店鋪運營
*/
public void operate();
/**
* 店鋪交易
*/
public void business();
}
複製程式碼
PersonStore.java(RealSubject) 單個使用者運營
public class PersonStore implements Store {
@Override
public void operate() {
System.out.println("個人商店運營");
}
@Override
public void business() {
System.out.println("個人商店交易");
}
}複製程式碼
靜態代理
靜態代理的實現比較簡單,代理類通過實現與目標物件相同的介面,並在類中維護一個代理物件,這種場景用於個體商家比較少的情況,如果多的話代理類十分繁多、不易維護
建立靜態代理類
ProxyStroe.java(proxy):在代理平臺運營是收取管理費用100,這個代理類需要實現Store介面,並制定目標類target(PersonStore)。
public class ProxyStroe implements Store{
private Store personStore = new PersonStore();
@Override
public void operate() {
System.out.println("收取管理費用100元");
personStore.operate();
}
@Override
public void business() {
personStore.business();
}
}複製程式碼
靜態代理呼叫
StaticConsumer.java(client):通過建立ProxyStroe去代理PersonStore,並進行操作。
public class StaticConsumer {
public static void main(String[] args) {
ProxyStroe store = new ProxyStroe();
store.operate();
store.business();
}
}複製程式碼
動態代理
JDK代理
動態代理類是通過介面實現的,利用攔截器(攔截器必須實現InvocationHanlder)加上反射機制生成一個實現代理介面的匿名類,在呼叫具體方法前呼叫InvokeHandler來處理。
建立jdk代理類
JDKStoreHandler.java(proxy):通過實現InvocationHandler介面的invoke方法,在裡面進行反射呼叫,newProxyInstanse通過目標物件建立真是物件。
public class JDKStoreHandler implements InvocationHandler {
/**
* 目標物件
*/
private Object targetObject;
@Override
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable {
if("operate".equals(method.getName())){
System.out.println("收取管理費用100元");
}
return method.invoke(targetObject,args);
}
/**
*
* @param targetObject
* @return
*/
public Object newProxyInstanse(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
}
}複製程式碼
JDK代理物件呼叫
JDKDynamicConsumer.java(proxy):通過JDKStoreHandler的newProxyInstanse建立真實目標物件,並呼叫介面的方法
public class JDKDynamicConsumer {
public static void main(String[] args) {
Store store = (Store)new JDKStoreHandler().newProxyInstanse(new PersonStore());
store.operate();
store.business();
}
}
複製程式碼
CGLIB代理
cglib動態代理是利用asm開源包,對代理物件類的class檔案載入進來,通過修改其位元組碼生成子類來處理。
建立cglib代理物件
CglibProxy.java(proxy):需要實現MethodInterceptor的intercept方法,並進行反射呼叫。通過createProxyObject建立真實物件,這裡是根據目標物件直接生成物件。
public class CglibProxy implements MethodInterceptor{
/**
* CGlib需要代理的目標物件
*/
private Object targetObject;
public Object createProxyObject(Object targetObject){
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;
}
@Override
public Object intercept(Object o,Object[] objects,MethodProxy methodProxy) throws Throwable {
if("operate".equals(method.getName())){
System.out.println("收取管理費用100元");
}
return method.invoke(targetObject,objects);
}
}複製程式碼
CGLib代理物件呼叫
CglibDynamicConsumer.java(client):通過CglibProxy的createProxyObject建立真實目標物件,對進行方法呼叫
public class CglibDynamicConsumer {
public static void main(String[] args) {
Store store = (Store)new CglibProxy().createProxyObject(new PersonStore());
store.operate();
store.business();
}
}
複製程式碼
原始碼已上傳:https://github.com/itrickzhang/proxy-demo