JDK6提供了Javacompiler,StandardJavaFileManager,Iterable
实现对.java文件编译的方法。
框架在实现代理的时候可以使用CGLIB直接生成2进制文件,不需要生成.java文件。
//接口
public interface Moveable {
void move();
void stop();
}
//实现Moveable接口
public class Tank implements Moveable{
public void move() {
System.out.println("tank move()...");
}
public void stop() {
System.out.println("tank stop()...");
}
}
import java.lang.reflect.Method;
//除moveable之外再创建一个接口InvocationHandler
public interface InvocationHandler {
void invoke(Object o,Method m);
}
import java.lang.reflect.Method;
//实现InvocationHandler接口,自定义需要添加的内容,创建添加日志的Handler
public class LogHandler implements InvocationHandler{
Object target;
public LogHandler(Object target) {
this.target = target;
}
public void invoke(Object o, Method m) {
System.out.println("logHandler start...");
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("logHandler end...");
}
}
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;
//模拟JDK的代理类Proxy
public class Proxy {
//模拟JDK创建代理类的方法,JDK中还有一个ClassLoader参数,这里传入接口和需要添加的逻辑Handler,结果返回一个代理的对象。
public static Object newProxyInstance(Class inf,InvocationHandler h) throws Exception{
String methodStr = "";
String rt = "\r\n";
Method[] methods = inf.getMethods();
for(Method m : methods){
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + inf.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
//生成代理对象的类
String src =
"package proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + inf.getName() + "{" + rt +
" proxy.InvocationHandler h;" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
methodStr +
"}";
String fileName =
"D:/share/test/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);//生成.java文件
fw.flush();
fw.close();
//对类进行编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable units = fileManager.getJavaFileObjects(fileName);
compiler.getTask(null, fileManager, null, null, null, units).call();//编译,生成.class文件。
fileManager.close();
URL[] url = new URL[]{new URL("file:/D:/share/test/")};
URLClassLoader loader = new URLClassLoader(url);
Constructor c = loader.loadClass("proxy.$Proxy1").getConstructor(InvocationHandler.class);//构造器有参数
return c.newInstance(h);//加载.class文件,生成对象。
}
}
public class Client {
public static void main(String[] args) throws Exception {
InvocationHandler h = new LogHandler(new Tank());//告诉代理类,我需要添加什么逻辑。
Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);//返回代理的对象。
m.move();//实际这里是调用添加过逻辑的代理类的方法。
m.stop();
}
}