設計模式之-代理模式(Proxy)

代理(Proxy)模式標準定義:爲其餘對象提供一種代理以控制對這個對象的訪問。java

代理就是一我的或一個機構表明另外一我的或者一個機構採起行動。某些狀況下,客戶不想或者不可以直接引用一個對象,代理對象能夠在客戶和目標對象直接起到中介的做用。客戶端分辨不出代理主題對象與真實主題對象。代理模式能夠並不知道真正的被代理對象,而僅僅持有一個被代理對象的接口,這時候代理對象不可以建立被代理對象,被代理對象必須有系統的其餘角色代爲建立並傳入。ide

代理模式實現的方式具體有2種。一、經過繼承實現;二、經過聚合的方式實現。this

 

/**url

* @describe: 定義接口.net

*/代理

public interface Animal {對象

    public void move();blog

}繼承

 

/**接口

* @describe: 接口實現類

*/

package test.com.java.proxy.example;

public class Persion implements Animal{

 

@Override

public void move() {

    System.out.println("不斷的移動中...");

    try {

        Thread.sleep(1000);

    } catch (InterruptedException e) {

        e.printStackTrace();

    }

    System.out.println("移動結束...");

    }

}

 

/**

*

* @describe:一、採用繼承的方式對Persion進行代理,增長打印方法執行時間的新功能

*/

package test.com.java.proxy.example;

public class PersionExtendsProxy extends Persion{

 

@Override

public void move() {

    long start=System.currentTimeMillis();

    System.out.println("move() start...");

    super.move();

    long end=System.currentTimeMillis();

    System.out.println("move() end... times:"+(end-start));

    }

}

 

/**

*

* @describe:二、採用聚合的方式對Proxy類進行代理(面向接口的方式代理)

*/

package test.com.java.proxy.example;

public class PersionProxy implements Animal{

 

    private Animal a;

    public PersionProxy(Animal a){

    this.a=a;

}

@Override

public void move() {

    long start=System.currentTimeMillis();

    System.out.println("move() start...");

    a.move();

    long end=System.currentTimeMillis();

    System.out.println("move() end... times:"+(end-start));

    }

}

 

package test.com.java.proxy.example;

public class Test {

    public static void main(String[] args) {

    //採用繼承的方式實現代理

    Animal proxy=new PersionExtendsProxy();

    proxy.move();

    System.out.println("----------------------------------");

    //採用聚合的方式實現代理

    Persion p=new Persion();

    Animal proxy1=new PersionProxy(p);

    proxy1.move();

    }

}

 

運行結果:

move() start...

不斷的移動中...

移動結束...

move() end... times:1000

----------------------------------

move() start...

不斷的移動中...

移動結束...

move() end... times:1001

 

2種實現方式比較:

1)因爲java僅支持單繼承,因此採用繼承的方式實現不夠靈活,若是還須要繼承其餘的類的話,那就費了;

2)若是須要繼續增長新的代理功能,那麼採用繼承的方式的話,就須要不斷的繼承下去,這樣類的層次結構會愈來愈深,維護起來很不方便。

綜上所述:採用聚合的方式實現代理比較好。下面咱們討論下JDK動態代理實現。

JDK動態代理實現以下:

Animal.java、Persion.java文件同上

下面須要咱們自定義一個實現InvocationHandler接口的處理方法類,在要代理的對象方法先後增長適當的邏輯。

 

package test.com.java.proxy.dynamic;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

 

public class MyInvocationHandler implements InvocationHandler{

 

private Object target;

MyInvocationHandler() {

    super();

}

MyInvocationHandler(Object target) {

    super();

    this.target = target;

}

@Override

public Object invoke(Object o, Method method,Object[] args) throws Throwable {

    System.out.println("o:"+o.getClass().getName());

    System.out.println("method:"+method);

    System.out.println("args:"+args);

    long start=System.currentTimeMillis();

    System.out.println("move() start...");

    Object result=method.invoke(target, args);

    long end=System.currentTimeMillis();

    System.out.println("move() end... times:"+(end-start));

    System.out.println("result:"+result);

    return result;

}

 

}

 

/**

*

* @describe:使用JDK動態代理的方式

* @author wenqi 2017年11月26日

*

*/

package test.com.java.proxy.dynamic;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

 

public class Test {

public static void main(String[] args) {

    Animal a=new Persion();

    InvocationHandler handler=new MyInvocationHandler(a);

    Animal proxy=(Animal) Proxy.newProxyInstance(a.getClass().getClassLoader(), a.getClass().getInterfaces(), handler);

    proxy.move();

    }

}

 

運行結果以下:

o:com.sun.proxy.$Proxy0

method:public abstract void test.com.java.proxy.dynamic.Animal.move()

args:null

move() start...

不斷的移動中...

move() end... times:1002

result:null

 

生成動態代理Class文件相似以下:

 

public class Proxy {

public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {

    String methodStr = "";

    String rt = "\r\n";

    Method[] methods = infce.getMethods();

    for(Method m : methods) {

    methodStr += "@Override" + rt +

    "public void " + m.getName() + "() {" + rt +

    " try {" + rt +

    " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +

    " h.invoke(this, md);" + rt +

    " }catch(Exception e) {e.printStackTrace();}" + rt +

    "}";

    }

 String src =

"package com.bjsxt.proxy;" + rt +

"import java.lang.reflect.Method;" + rt +

"public class $Proxy1 implements " + infce.getName() + "{" + rt +

" public $Proxy1(InvocationHandler h) {" + rt +

" this.h = h;" + rt +

" }" + rt +

" InvocationHandler h;" + rt +

methodStr +

"}";

String fileName =

"d:/src/$Proxy1.java";

File f = new File(fileName);

FileWriter fw = new FileWriter(f);

fw.write(src);

fw.flush();

fw.close();

//compile

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);

Iterable units = fileMgr.getJavaFileObjects(fileName);

CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);

t.call();

fileMgr.close();

//load into memory and create an instance

URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};

URLClassLoader ul = new URLClassLoader(urls);

Class c = ul.loadClass("$Proxy1");

System.out.println(c);

Constructor ctr = c.getConstructor(InvocationHandler.class);

Object m = ctr.newInstance(h);

 

return m;

}

}

 

Spring中aop是動態代理具體應用,相關文章以下:

http://blog.csdn.net/guoquanyou/article/details/6754916

相關文章
相關標籤/搜索