代理模式-靜態代理與動態代理
阿新 • • 發佈:2018-03-31
應用 代碼 creat HR print tps 結果 inter OS
簡介
- 首先感謝沽泡學院 tom 老師
- 代理模式是一種結構型模式
- 代理模式就是代理對象幫被代理對象處理一些問題, 類似中介, 客戶只要結果, 中介怎麽搞是他的事兒, 他可能再處理過程中賺外快什麽的
- 代理模式的應用: spring中的aop, 日常工作中記錄日誌, 統計時間,權限控制等
- 這裏我們使用一個客戶端代理訪問google舉例, 具體細節可能不合適, 意會、意會、意會...
靜態代理
/** * 一個服務器接口, 服務器有很多功能, 可以用來路由, 建站等... */ public interface Server { boolean internetgoogle(Boolean ispass); boolean internetbaidu(Boolean ispass); }
/** * @ClassName: HKProxyServer * @description [靜態代理類, 幫助被代理對象訪問url, 靜態代理類和被代理對象實現同一接口, 唯一的區別就是代理類持有被代理對象引用, ] * 每次修改接口, 代理類和被代理類都要實現相同的方法, 靜態代理, 要做的事情已經是確定的, 只是表面上換了個人去做 * @create 2018-03-31 上午7:56 **/ public class HKProxyServer implements Server{ //傳入客戶端信息 private Server client; public HKProxyServer(Server client) { this.client = client; } @Override public boolean internetgoogle(Boolean ispass) { System.out.println("香港代理: "); return client.internetgoogle(true); } @Override public boolean internetbaidu(Boolean ispass) { System.out.println("香港代理: "); return client.internetbaidu(true); } }
/** * @ClassName: ChinaServer * @description [描述該類的功能] * @create 2018-03-31 上午7:45 **/ public class ChinaClient implements Server { @Override public boolean internetgoogle(Boolean ispass) { if(ispass != null && ispass){ System.out.println(" 請求地址: www.google.com 通過"); return true ; }else{ System.out.println(" 請求地址: www.google.com 拒絕"); return false; } } @Override public boolean internetbaidu(Boolean ispass) { System.out.println(" 請求地址: www.baidu.com 通過"); return true; } }
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
Server chinaServer = new ChinaClient();
//訪問不了google
Assert.assertFalse(chinaServer.internetgoogle(null));
//可以訪問baidu
Assert.assertTrue(chinaServer.internetbaidu(null));
System.out.println("--------------------------------------------------通過代理訪問--------------------------------------------------");
Server proxyServer = new HKProxyServer(chinaServer);
//可以訪問google
Assert.assertTrue(proxyServer.internetgoogle(null));
//可以訪問baidu
Assert.assertTrue(proxyServer.internetbaidu(null));
}
}
jdk實現動態代理
/**
* @ClassName: HKProxyServer
* @description [使用jdk動態代理實現, 不用實現與被代理類相同的接口, 接口增加方法也與我無關, 動態調用被代理類方法,
* 在調用方法前我可以輸出日誌, aop, 但是調用的方法的對象是傳入的client對象]
* @create 2018-03-31 上午7:56
**/
public class HKProxyServer implements InvocationHandler {
//傳入客戶端信息
private Server client;
public HKProxyServer(Server client) {
this.client = client;
}
public Object getInstence(){
Class<?> clazz = client.getClass();
//用來生成一個新的對象(字節碼重組來實現)
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
//如果直接返回傳入對象就不會調用下面的invoke方法
// return client;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
args = new Object[]{true};//代理執行方法前可以搞事情
System.out.println("mylog +++++++++ 動態代理調用方法 " + method.getName());
return method.invoke(this.client, args);
}
}
/**
* @ClassName: ChinaServer
* @description [描述該類的功能]
* @create 2018-03-31 上午7:45
**/
public class ChinaClient implements Server {
@Override
public boolean internetgoogle(Boolean ispass) {
System.out.println(this);
if(ispass){
System.out.println("請求地址: www.google.com 通過");
return true ;
}else{
System.out.println("請求地址: www.google.com 拒絕");
return false;
}
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println(this);
System.out.println("請求地址: www.baidu.com 通過");
return true;
}
}
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
//代理對象內部使用傳入de被代理對象調用方法(等價 new Object().methodxx())
Server chinaClient = new ChinaClient();
Server proxyServer = (Server)new HKProxyServer(chinaClient).getInstence();
Assert.assertTrue(proxyServer.internetgoogle(false));
Assert.assertTrue(proxyServer.internetbaidu(true));
Assert.assertFalse(chinaClient.equals(proxyServer));
}
}
cglib實現動態代理
/**
* @ClassName: HKProxyServer
* @description [使用cglib實現動態代理, 客戶端都不用創建對象, 對象由框架創建載入, 體現在客戶端像是用接口調用方法]
* @create 2018-03-31 上午7:56
**/
public class HKProxyServer implements MethodInterceptor {
public Object getInstence(Class<?> clazz){
Enhancer enhancer = new Enhancer();
//要把哪個設置為即將生成的新類父類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("mylog +++++++++++++++ cglib代理實現: 調用方法" + method.getName());
return methodProxy.invokeSuper(o,objects);
}
}
public class ChinaClient implements Server {
@Override
public boolean internetgoogle(Boolean ispass) {
System.out.println(this);
if(ispass){
System.out.println("請求地址: www.google.com 通過");
return true ;
}else{
System.out.println("請求地址: www.google.com 拒絕");
return false;
}
}
@Override
public boolean internetbaidu(Boolean ispass) {
System.out.println(this);
System.out.println("請求地址: www.baidu.com 通過");
return true;
}
}
public class AccessGoogle {
@Test
public void tryToAccessGoogle(){
//不需要再new對象,傳入chinaclient.class即可, 然後使用接口調用方法, 內部創建了個新的子類對象來調用指定方法
Server proxyServer = (Server)new HKProxyServer().getInstence(ChinaClient.class);
Assert.assertTrue(proxyServer.internetgoogle(true));
Assert.assertTrue(proxyServer.internetbaidu(true));
}
}
三種代理方式的分析
- 靜態代理: 要做的事情已經是確定的, 只是表面上換了個人去做,代理對象和被代理對象實現同樣的接口,實際通過傳入對象調用
- jdk動態代理: 與靜態代理效果相同, 但是java通過反射實現代理類不用實現與被代理對象同樣的接口, 也可以根據傳入方法調用被代理對象的方法, 傳入對象調用
- cglib動態代理: 只需要傳入被代理對象的類名, 內部會實現創建對象到調用的過程,客戶端不需要創建具體的對象, 接口調用方法
代碼路徑
https://github.com/offline7LY/designpattern
代理模式-靜態代理與動態代理