jdk中动态代理的实现
Client
package com.dp.proxy;
import java.io.Serializable;
/**
* 动态代理
* */
public class Client {
public static void main(String[] args) {
Moveable t = new Tank();
InvocationHandler h = new TimeHandler(t); //对t的时间代理操作
Moveable m = (Moveable)new Proxy().newProxyInstance(Moveable.class,h);
m.move();
}
}
/*
D:\eclipse-workspace\Proxy-jdk
com.sun.tools.javac.api.JavacTool
class com.dp.proxy.TankTimeProxy
Tank moving
time:751
*/
Moveable
package com.dp.proxy;
public interface Moveable {
void move();
}
Tank
package com.dp.proxy;
import java.util.Random;
public class Tank implements Moveable{
public void move() {
System.out.println("Tank moving");
try { //此线程休眠1000毫秒以内随机数
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
InvocationHandler
package com.dp.proxy;
import java.lang.reflect.Method;
/**
* 对任意方法进行自定义处理
* 具体处理放在实现类中
* */
public interface InvocationHandler {
public void invoke(Object o,Method m);
}
TimerHandler
package com.dp.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 对被代理的类加一些时间的逻辑处理
* */
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public void invoke(Object o,Method m) {
long start = System.currentTimeMillis(); //加入代理逻辑
try {
m.invoke(target); //简单起见假设参数为空 调用方法target.m()
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time:"+(end-start));
}
}
Proxy
package com.dp.proxy;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
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;
/**
* JDK Compiler API,
* CGLib,ASM 直接生成二进制文件
* 根据被代理的类实现的接口和要进行的具体的代理操作的类动态实现代理
* 可以对任意的对象、任意的接口方法,实现任意的代理
* */
public class Proxy {
public static Object newProxyInstance(Class intfce,InvocationHandler h) {
String rt = "\r\n"; //回车和换行
String methodStr = "";
Method[] methods = intfce.getMethods();
for(Method m:methods) {
methodStr +=
" @Override"+rt+
" public void "+m.getName()+"() {"+ rt + //简单起见假设这里方法都为void
" Method method = null;"+rt+
" try {"+rt+
" method = "+intfce.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+
" } catch (NoSuchMethodException | SecurityException e) {" + rt +
" e.printStackTrace();" +rt +
" }"+rt+
" h.invoke(this,method);"+ rt +
" }"+ rt ;
}
String src =
"package com.dp.proxy;"+ rt +
"import java.lang.reflect.Method;"+rt+
"public class $proxy1 implements "+intfce.getName()+"{"+ rt +
" InvocationHandler h;"+rt+
" public $proxy1(InvocationHandler h) {"+ rt +
" super();"+ rt +
" this.h = h;"+ rt +
" }"+ rt +
methodStr+
"}";
String fileName = System.getProperty("user.dir");
System.out.println(fileName);//项目根路径 D:\eclipse-workspace\Proxy-jdk
fileName = fileName+"/src/com/dp/proxy/$proxy1.java";
File f = new File(fileName);
try {
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
//compile javac
//得到编译器对象
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//编译文件时,会找到JAVA_HOME的jre\lib\tools.jar,但tools.jar并不在jre中,它是在jdk\lib
//值为null的解决办法:将jdk\lib下将tools.jar复制到jre\lib下
System.out.println(compiler.getClass().getName());//com.sun.tools.javac.api.JavacTool
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable utils = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, utils);
t.call();
try {
fileMgr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//生成了.class文件
//load into memory and create an instance
URL[] urls = null;
try {
urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/")};
} catch (MalformedURLException e) {
e.printStackTrace();
}
URLClassLoader ul = new URLClassLoader(urls);
try {
Class c = ul.loadClass("com.dp.proxy.$proxy1");
System.out.println(c); //class com.dp.proxy.TankTimeProxy
//拿到重载的构造方法
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object o = (Object)ctr.newInstance(h);
return o;
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalArgumentException
| InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
生成的代理类$proxy1
package com.dp.proxy;
import java.lang.reflect.Method;
public class $proxy1 implements com.dp.proxy.Moveable{
InvocationHandler h;
public $proxy1(InvocationHandler h) {
super();
this.h = h;
}
@Override
public void move() {
Method method = null;
try {
method = com.dp.proxy.Moveable.class.getMethod("move");
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
h.invoke(this,method);
}
}
test包
Client
package com.dp.proxy.test;
import com.dp.proxy.InvocationHandler;
import com.dp.proxy.Proxy;
public class Client {
public static void main(String[] args) {
UserMgr u = new UserMgrImpl();
InvocationHandler h = new TransactionHandler(u);
UserMgr um = (UserMgr)Proxy.newProxyInstance(UserMgr.class, h);
um.addUser();
}
}
/*
D:\eclipse-workspace\Proxy-jdk
com.sun.tools.javac.api.JavacTool
class com.dp.proxy.$proxy1
Transaction start
1.插入记录到User表
2.做日志到另外一张表
Transaction commit
*/
UserMgr
package com.dp.proxy.test;
public interface UserMgr {
void addUser();
}
UserMgrImpl
package com.dp.proxy.test;
public class UserMgrImpl implements UserMgr{
@Override
public void addUser() {
System.out.println("1.插入记录到User表");
System.out.println("2.做日志到另外一张表");
}
}
TranscationHandler
package com.dp.proxy.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.dp.proxy.InvocationHandler;
public class TransactionHandler implements InvocationHandler{
private Object target;
public TransactionHandler(Object o) {
super();
this.target = o;
}
@Override
public void invoke(Object o, Method m) {
System.out.println("Transaction start");
try {
m.invoke(target);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("Transaction commit");
}
}
生成的代理类$proxy1
package com.dp.proxy;
import java.lang.reflect.Method;
public class $proxy1 implements com.dp.proxy.test.UserMgr{
InvocationHandler h;
public $proxy1(InvocationHandler h) {
super();
this.h = h;
}
@Override
public void addUser() {
Method method = null;
try {
method = com.dp.proxy.test.UserMgr.class.getMethod("addUser");
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
h.invoke(this,method);
}
}