下面是手写模拟了JDK动态代理的过程,几乎每行我都会注释
看之前需要了解的
1,对反射有所了解
2,对动态代理的过程有所了解
3,对阅读理解源码困难(大神就不用啦,有不足或错误的地方希望有大神指点一下)
目录结构
代码实现
接口类
package com.liao.dao;
public interface UserDao {
public void query(String name);
}
目标实现类
package com.liao.dao;
public class UserDaoImpl implements UserDao {
@Override
public void query(String name) {
System.out.println("name = " + name);
}
}
模拟动态代理过程的代理类
package com.liao;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
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.URL;
import java.net.URLClassLoader;
/**
* 得到一个java文件
* 编译成一个class文件
* 通过反射得到一个对象
* return 代理对象
*/
public class ProxyUtil {
public static Object newProxyInstance(Object target) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
String content="";
String packageContent="package com.liao;";//定义包名,先写死
Class targetInfo=target.getClass().getInterfaces()[0];//获取该类的实现的第一个接口
String targetInfoName=targetInfo.getSimpleName();//只是简单的获取接口类的名字
String improtContent="import "+targetInfo.getName()+";";//导对应的类包
String classContent="public class $Proxy implements "+targetInfoName+"{";
/**
* 下面是所要代理的类里面的内容
*/
String fieldContent="private "+targetInfoName+" target;";//接口类的属性对象
String construterContent="public $Proxy("+targetInfoName+" target) {"
+"this.target=target;}";//代理类的构造方法
String methodContent="";
Method[] methods=targetInfo.getDeclaredMethods();//获取所有的私有方法
for (Method method : methods) {//方法拼接
String methodName=method.getName();//获取方法名
Class returnType=method.getReturnType();//获取方法的返回类型
Class<?>[] parameterTypes=method.getParameterTypes();//获取参数
String argsContent = "";
String argsNames = "";
int i=0;
for (Class<?> parameterType : parameterTypes) {
String simpleName = parameterType.getSimpleName();//获取参数类型
/**
* 自定义参数名字为pi
*/
argsContent+=simpleName+" p"+i+",";
argsNames+="p"+i+",";
i++;
}
/**
* 把参数类型的最后一个逗号点截取掉
*/
if(argsContent.length()>0){
argsContent= argsContent.substring(0,argsContent.lastIndexOf(",")-1);
argsNames= argsNames.substring(0,argsNames.lastIndexOf(",")-1);
}
/**
* 拼接方法,模拟自定义输出
*/
methodContent = "public "+returnType+" "+methodName+"("+argsContent+"){"
+" System.out.println(\"日志输出log...\");"//这里可以加入一些其他实际的方法
+"target."+methodName+"("+argsNames+");}";//调用目标方法输出
}
//这个content包含了一整个类的所有内容,然后存到硬盘去
content+=packageContent+improtContent+classContent+fieldContent+construterContent+methodContent+"}";
File file=new File("d:\\com\\liao\\$Proxy.java");
if(!file.exists()){//如果文件不存在则新建一个
file.createNewFile();
System.out.println("file = " + file);
}
FileWriter fileWriter=new FileWriter(file);
fileWriter.write(content);//把内容写进文件
fileWriter.flush();//刷新文件
fileWriter.close();//最后关闭
/**
* 下面是把.java文件编译为.class文件
*/
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
task.call();
/**
* 把.class文件加载到进程中去,并通过反射实例化对象
*/
URL[] urls = new URL[]{new URL("file:d:\\\\")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass("com.liao.$Proxy");
Constructor constructor = clazz.getConstructor(targetInfo);
Object proxy = constructor.newInstance(target);//实例化代理对象,并返回出去
return proxy;
}
}
测试类
package com.liao.test;
import com.liao.ProxyUtil;
import com.liao.dao.UserDao;
import com.liao.dao.UserDaoImpl;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class TestProxy {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
UserDao userDao=new UserDaoImpl();
UserDao proxy = (UserDao) ProxyUtil.newProxyInstance(userDao);
proxy.query("华安");
}
}
测试结果