由微見著,模擬JDK動態代理的實現1

話說代理說白了就是方法的再封裝,實現代理是由繼承和聚合兩種方式實現的。動態代理就是使用代理類在運行時根據傳入的接口類型的對象,生成class文件,實例化,並調用裏面的代理方法。


以下是例子(code):


/**
 * 使用聚合來實現代理-代理和被代理也是實現Moveable(自定義Interface)
 * 本類是模擬代理的測試端
 * @author Rick
 *
 */
public class Client {
public static void main(String[] args) throws Exception {
// Tank t = new Tank();
/*TankTimeProxy ttp = new TankTimeProxy(t);
TankLogProxy tlp = new TankLogProxy(ttp);*/

/**
* 替換代理順序
*/
/*TankLogProxy tlp = new TankLogProxy(t);
TankTimeProxy ttp = new TankTimeProxy(tlp);
Moveable m = ttp;
m.move();
*/

/**
* 以上是靜態代理,以下是動態代理,動態代理是不需要知道TankTimeProxy類的名字
*/

/**
* 能作爲各種類對象的代理
*/
Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class);//所有代理由此方法產生
m.move();
}
}


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

public interface Moveable {
void move();
}


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

/**
 * 實現任意接口的類的代理-使用聚合代理
 * 代理模式有聚合代理和實現繼承的代理
 * 繼承的方式的缺點就是:n級代理就需要n級繼承關係
 * @author Rick
 *
 */
public class Proxy {
public static Object newProxyInstance(Class infce) throws Exception {//實現動態編譯  --JDK Complier 
String methodString = "";
String rt = "\r\n";

Method[] methods = infce.getMethods();
for(Method m : methods) {
methodString += "@Override" + rt + 
"public void " + m.getName() + "() {" + rt + 
" long start = System.currentTimeMillis();" + rt +
" System.out.println(\"start time : \" + start);" + rt +
" t."+ m.getName() + "();" + rt +
" long end = System.currentTimeMillis();" + rt +
" System.out.println(\"時間代理類運行時間: \" + (end - start));" + rt +
"}";
}

String src = 
"package com.tamao.dynamicAgent;" + rt +
"public class TankTimeProxy implements "+ infce.getName() +" {" + rt +

   "    Moveable t;" + rt +
" public TankTimeProxy(Moveable t) {" + rt +

" super();" + rt +
" this.t = t;" + rt +
"    }" + rt +


methodString + 
"}";

String fileName = System.getProperty("user.dir") 
+ "/src/com/tamao/dynamicAgent/TankTimeProxy.java";

File f = new File(fileName);;
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();

/**
* JDK6.0纔有編譯器
*/

//編譯以上代碼
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來的類
URL[] urls = new URL[] {new URL("file://" + System.getProperty("user.dir") + "/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.tamao.dynamicAgent.TankTimeProxy");
System.out.println(c);

/**
* 站在JVM的角度,拿到類的構造方法的對象(PS:找到方法是根據參數來決定的)
*/

//找到參數類型是Moveable的參數類型的構造方法
Constructor ctr = c.getConstructor(Moveable.class);
Object m = ctr.newInstance(new Tank());
return m;
}


}


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


public class Tank implements Moveable {


@Override
public void move() {
long start = System.currentTimeMillis();
System.out.println("moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Tank運行時間: " + (end - start));
}




}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章