代理(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{
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{
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是動態代理具體應用,相關文章以下: