1. 程式人生 > >java設計模式—動態代理模式

java設計模式—動態代理模式

類定義:

1、被代理介面和實現類:Tank類實現了Moveable介面,能夠move()

package com.zec.disignmode;
public interface Moveable {
public void move();
}

package com.zec.disignmode;
import java.util.Random;
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank moving....");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2、代理加工介面和實現類:TimeHandler類實現了InvocationHandler介面,能夠invoke(Object object,Method m)在object的m方法前後加上自己記錄時間的邏輯,並不是代理類,只是提供了對被代理類的加工邏輯;

package com.zec.disignmode;
import java.lang.reflect.Method;
public interface InvocationHandler {
public void invoke(Object o,Method m);
}

package com.zec.disignmode;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler{
@Override
public void invoke(Object object, Method m) {
System.out.println("Time Before "+m.getName());
try {
m.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Time After "+m.getName());
}

}

3、生成動態代理類的Proxy靜態類:代理產生器,根據傳進來的引數Class Intface和InvocationHandler h,產生動態代理類;從而使intface中的所有方法都加上了h中invoke方法的自定義邏輯;為了便於代理類的組合和擴充套件,代理類也會實現Intface介面,最終返回一個代理類物件;

package com.zec.disignmode;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
public class Proxy {
public static Object newInstance(Class intface,InvocationHandler h) throws Exception {
/*Generate the source code*/
String rt = "\r\n";
String methodStr = "";
for (Method method:intface.getMethods()) {
methodStr +=
" @Override"+rt+
" public void "+ method.getName() +"() {"+rt+
" try{"+rt+
" Method m = "+ intface.getName()+".class.getMethod(\""+ method.getName() +"\");" + rt+
" h.invoke(tank,m);"+rt+
" }catch(Exception e){e.printStackTrace();}"+rt+
" }"+rt
;
}
String src =
"package com.zec.disignmode;"+rt+
"import java.util.Random;"+rt+
"import java.lang.reflect.*;"+rt+
"public class TankTimeProxy implements "+ intface.getName() +"{"+rt+
" "+ intface.getName() +" tank;"+rt+
" com.zec.disignmode.InvocationHandler h;"+rt+
" public TankTimeProxy("+ intface.getName() +" t,com.zec.disignmode.InvocationHandler h) {"+rt+
" tank = t;"+rt+
" this.h = h;"+rt+
" }"+rt+
methodStr+
"}";
/*Generate the java file*/
String fileName = System.getProperty("user.dir")+"/src/com/zec/disignmode/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
/*Generate the class file*/
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager jfMgr = jc.getStandardFileManager(null, null, null);
Iterable units = jfMgr.getJavaFileObjects(fileName);
CompilationTask ct = jc.getTask(null, jfMgr, null, null, null, units);
ct.call();
jfMgr.close();
/*Load the class into the memory*/
URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/src")};
URLClassLoader urlLoader = new URLClassLoader(urls);
Class c = urlLoader.loadClass("com.zec.disignmode.TankTimeProxy");
/*Generate the object*/
Constructor constructor = c.getConstructor(Moveable.class,InvocationHandler.class);
Object moveable = constructor.newInstance(new Tank(),h);
return moveable;
}
}

4、測試類

package com.zec.disignmode;
public class Client {
public static void main(String[] args) {
Moveable m = new Tank();
LogHandler h = new LogHandler();
try {
Moveable moveable = (Moveable) Proxy.newInstance(Moveable.class, h);
moveable.move();
} catch (Exception e) {
e.printStackTrace();
}
}
}

5、學習心得:

(1)為了增強代理類的可擴充套件性,代理類和被代理類實現的是同一個介面,這樣代理類可以作為被代理類再次被代理,可以實現不同功能代理的組合,本例中為Moveable;

(2)InvocationHandler介面定義了對特定物件的方法的代理加工方法,Proxy為代理生成器,newInstance(Class intface,InvocationHandler h)方法表示對intface介面的所有方法進行加工,加工的邏輯由h的invoke方法定義;

(3)代理生成器最後返回一個intface型別的引用,指向已經生成的動態代理類;

(4)對於使用者來說,不必關心動態代理類的名稱,只需要指定要代理的介面型別和處理類就可以了。