前言:
上一篇讲到
jdk动态代理
的实现
现在来讲一下自己动手实现java 动态代理
上一篇: jdk 动态代理
2. 自定义实现:
分析:
想要自定义实现,有5个步骤:
- 生成增强类源代码
- 把源代码输出到磁盘
- 编译成class文件
- 加载到jvm中
- 返回被代理后的代理对象
首先我们需要拥有自己的GPProxy, GPInvocationHandler,GPMeipo, GPClassLoader
这样四个类
- GPProxy: 自定义的Proxy类,里面有生成源代码的方法,把源代码输出到磁盘的方法,把.java编译成.class的方法
- GPInvocationHandler: 自定义的媒婆需要实现的接口
- GPMeipo: 自定义的媒婆
- GPClassLoader: 自定义的类加载器,里面有把生成的.class文件加载到jvm中的方法
代码
GPPRoxy:
public class GPProxy {
// 定义换行符
private static String ln = "\r\n";
protected GPInvocationHandler h;
public static Object newProxyInstance(GPClassLoader loader, Class<?>[] interfaces, GPInvocationHandler h)
throws IllegalArgumentException {
try {
String className = "$Proxy";
// 1.生成源代码
String classSrc = generateJava(className, interfaces[0]);
// 2.把源代码输出到磁盘
String filepath = GPProxy.class.getResource("").getPath() + className + ".java";
File f = generateSrcOnDisk(classSrc, filepath);
// 3.编译成class文件
compilerClass(f);
// 4.加载到jvm中
// 找到对应类
Class<?> proxyClass = loader.findClass(className);
// 5.返回被代理后的代理对象
// 选择构造方法
Constructor<?> constructor = proxyClass.getConstructor(GPInvocationHandler.class);
// 构造对象
return constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return h;
}
/**
* 通过接口生成class文件
*
* @param interfece
* @return
*/
public static String generateJava(String className, Class<?> intface) {
String packageName = GPProxy.class.getPackage().getName();
StringBuffer sb = new StringBuffer();
sb.append("package " + packageName + ";" + ln);
sb.append("import java.lang.reflect.Method;" + ln);
sb.append("public class " + className + " implements " + intface.getName() + "{" + ln);
sb.append("GPInvocationHandler h;" + ln);
// 构造方法
sb.append("public " + className + "(GPInvocationHandler h){" + ln);
sb.append("this.h = h;" + ln);
sb.append("}" + ln);
for (Method m : intface.getMethods()) {
// 成员方法
sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + intface.getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});"
+ ln);
sb.append("this.h.invoke(this,m,null);" + ln);
sb.append("}catch(Throwable e){" + ln);
sb.append(" e.printStackTrace();" + ln);
sb.append("}" + ln);
if (!m.getReturnType().getName().equals("void")) {
sb.append("return null;" + ln);
}
sb.append("}" + ln);
}
sb.append("}" + ln);
return sb.toString();
}
/**
* 在磁盘生成.java文件
*
* @param classSrc
* @param filepath
* @return
*/
public static File generateSrcOnDisk(String classSrc, String filepath) {
File f = null;
FileWriter fw = null;
try {
f = new File(filepath);
fw = new FileWriter(f);
fw.write(classSrc);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fw.flush();
fw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
return f;
}
/**
* 编译.java文件
*
* @param f
*/
public static void compilerClass(File f) {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager sm = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iterable = sm.getJavaFileObjects(f);
CompilationTask task = compiler.getTask(null, sm, null, null, null, iterable);
task.call();
try {
sm.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
GPMeipo :
public class GPMeipo implements GPInvocationHandler {
private Person source;
public Object getInstance(Person source) {
this.source = source;
Class<? extends Person> clazz = source.getClass();
return GPProxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆,相亲开始");
method.invoke(this.source, args);
System.out.println("相亲结束");
return null;
}
}
GPClassLoader :
public class GPClassLoader extends ClassLoader {
private File baseDir;
public GPClassLoader() {
String basepath = GPClassLoader.class.getResource("").getPath();
this.baseDir = new File(basepath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = GPClassLoader.class.getPackage().getName() + "." + name;
if (this.baseDir != null) {
File f = new File(this.baseDir, name.replace(".", "//") + ".class");
FileInputStream in = null;
ByteArrayOutputStream out = null;
if (f.exists()) {
try {
in = new FileInputStream(f);
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
out.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
return null;
}
}
总结:
能够自己动手实现一下提升还是挺大的,能够更深入的理解动态代理的实现过程以及动态代理的应用场景.