一.我對動態代理的理解
1.動態生成代理類java源文件
2.將代理類java源文件
編譯為代理類class字節碼
文件
3.將代理類class字節碼文件 自動加載到內存中
4.將自動加載到內存的代理類class字節碼進行實例化為 代理對象
5.有了代理對象,就可以使用代理對象中的方法調用被代理對象的方法了;
二.動態代理的實現流程
1.編寫接口MoveAble 有move方法
package proxy.statics;
/**
* 移動接口
* @author lxf
*
*/
public interface MoveAble {
public void move();
}
2.編寫被代理類Car實現MoveAble接口,并實現move方法寫業務羅輯;
package proxy.statics;
import java.util.Random;
/**
* 被代理類,汽車
* @author lxf
* @2017-07-06
*/
public class Car implements MoveAble {
@Override
public void move() {
//System.out.println("被代理對象---我是汽車對象本身:"+this.getClass().getName());
//實現開車
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽車行駛中...");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.編寫InvocationHandler接口(包含myinvoke方法)
注意:這里的InvocationHandler并不是java.lang.refect包下面的InvocationHandler
package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
* 事務處理接口
* @author lxf
*
*/
public interface InvocationHandler {
/**
* 參數:Object obj 屬于代理對象
* 參數:Method method 屬于代理對象的方法
*/
public void myinvoke(Object obj, Method method);
}
4.編寫TimerHandler類實現自己InvocationHandler接口中的myinvoke方法(用來調用被代理對象的方法,還有其他額外的業務邏輯)
package proxy.dynamic.custom;
import java.lang.reflect.Method;
/**
* 實現自己定義的事務處理接口proxy.dynamic.custom.InvocationHandler
* @author lxf
*
*/
public class TimerHandler implements InvocationHandler {
//代理對象
private Object target;
public TimerHandler(Object target) {
super();
this.target = target;
}
/**
* 參數:Object obj 屬于代理對象
* 參數:Method method 屬于代理對象的方法
*/
@Override
public void myinvoke(Object obj, Method method) {
// TODO Auto-generated method stub
try {
//開始時間 " + br +
Long start = System.currentTimeMillis();
System.out.println("汽車開始行駛...");
method.invoke(target);
//結束時間 " + br +
Long end = System.currentTimeMillis();
System.out.println("汽車結束行駛...行駛話費了:" + (end-start) + "ms");
//視頻聽到3-3 3:42秒
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.編寫生成代理類
的類Proxy,它的主要功能是 一步驟
中的所有流程;
package proxy.dynamic.custom;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
import javax.tools.JavaCompiler.CompilationTask;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
* 動態代理類
* @author lxf
* 參數:
* Class 代理類和被代理類實現的接口
* InvocationHandler h 自己實現的事務處理器proxy.dynamic.custom.TimerHandler
*
*/
public class Proxy {
/**
* 自己實現JDK生成動態代理類及對象
* @param infce 接口class,有了接口就可以通過接口獲取接口中定義的方法,為生成代理類而用
* @param h 自己創建的proxy.dynamic.custom.InvocationHandler 事務處理器(處理主要業務羅輯)
* 事務處理器中包含被代理對象Car,具體處理業務羅輯的代碼
* @return
* @throws IOException
*/
public static Object newProxyInstance(Class infce, InvocationHandler h) throws IOException
{
String br = "\n"; //換行符
String methodStr = "";
//獲取接口中所有的方法,遍歷組合為代理類的方法
for(Method m : infce.getMethods()){
methodStr += " @Override" + br +
" public void " + m.getName() + "() {" + br +
" try{" + br +
" Method md = " + infce.getName() + ".class.getMethod(\""
+ m.getName() + "\");" + br +
" h.myinvoke(this,md);" +br+
" }catch(Exception e){ e.printStackTrace();}" + br +
" }" ;
}
/**
* 動態代理類字符串
*/
String str =
" package proxy.dynamic.custom; " + br +
" import proxy.dynamic.custom.InvocationHandler; " + br +
" import java.lang.reflect.Method;" + br +
" public class $Proxy0 implements "+infce.getName()+"{ " + br +
" private InvocationHandler h; " + br +
" public $Proxy0( InvocationHandler h ) " + br +
" { " + br +
" this.h = h; " + br +
" } " + br +
methodStr + br +
"}";
/*
* 自行實現動態代理的流程
* 1. 動態生成代理類.java源文件
*/
//獲取當前項目路徑,/home/lxf/workspaceEE/proxy
String filename = System.getProperty("user.dir") + "/bin/proxy/dynamic/custom/$Proxy0.java";
System.out.println(filename);
File file = new File(filename);
FileUtils.writeStringToFile(file, str);
/*
* 2. 將動態生成的代理類.java源文件編譯為class字節碼文件
*/
//編譯
//拿到編譯器
JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr =
complier.getStandardFileManager(null, null, null);
//獲取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
//編譯任務
CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
//進行編譯
t.call();
fileMgr.close();
/**
* load到內存中
*/
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c;
try {
c = cl.loadClass("proxy.dynamic.custom.$Proxy0");
//System.out.println(c.getName());
//通過構造器返回代理對象
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
4.測試
package proxy.dynamic.custom;
import java.io.IOException;
import proxy.statics.Car;
import proxy.statics.MoveAble;
/**
* 測試自己實現JDK動態代理實現思路
* @author lxf
* @date 2017-07-07
*/
public class testMain {
public static void main(String[] args) throws IOException
{
//實例化被代理類
Car car = new Car();
//實例化事務處理器
InvocationHandler h = new TimerHandler(car);
//生成代理對象
MoveAble m = (MoveAble)Proxy.newProxyInstance(MoveAble.class,h);
//調用代理對象的方法
m.move();
}
}
執行結果:
/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java
汽車開始行駛...
汽車行駛中...
汽車結束行駛...行駛話費了:975ms
動態生成代理類/home/lxf/workspaceEE/proxy/bin/proxy/dynamic/custom/$Proxy0.java的代碼如下:
package proxy.dynamic.custom;
import proxy.dynamic.custom.InvocationHandler;
import java.lang.reflect.Method;
public class $Proxy0 implements proxy.statics.MoveAble{
private InvocationHandler h;
public $Proxy0( InvocationHandler h )
{
this.h = h;
}
@Override
public void move() {
try{
Method md = proxy.statics.MoveAble.class.getMethod("move");
h.myinvoke(this,md);
}catch(Exception e){ e.printStackTrace();}
}
}