今天研究了一下动态代理的生成,自己手动的拼接字符串写了一个,功能基本实现了,代码懒得优化了。废话不说直接贴代码,如有问题,欢迎指点。
package com.yang.proxy.dynamicproxy.proxy.jdk.util;
import org.apache.commons.lang.StringUtils;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description : 手写动态代理生成类
* Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承)
* Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效
* @date : 2019/12/20 16:23
*/
public class MyProxyUtil {
public static final String line = "\n";
public static final String tab = "\t";
public static AtomicInteger atomicInteger = new AtomicInteger(100);
//手写的动态代理生成代理类方法
public static Object getProxy(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler handler) throws Exception {
Object proxy = null;
//Class<?> targetClass = target.getClass();
//目标类的全限定名
//String targetName = targetClass.getName();
//目标类的包名
String targetackageName = "com.sun.proxy";
//String targetackageName = targetName.substring(0, targetName.lastIndexOf("."));
//目标类实现的接口们
//Class[] targetInterfaces = targetClass.getInterfaces();
String classContent = "";
//和目标类同一个包,避免引得的非public的包无权限访问
String packageContent = "package " + targetackageName + ";" + line;
//导入InvocationHandler包,因为要用到导入InvocationHandler包
String importContent = "import java.lang.reflect.InvocationHandler;" + line;
//导入所有接口包
for (Class targetInterface : interfaces) {
importContent += "import " + targetInterface.getName() + ";" + line;
}
//定义动态代理类类名$Proxy0123456789
int index = atomicInteger.incrementAndGet();
String clazzFirstLineContent = "public class $Proxy" + index + " implements ";
//实现目标类的所有接口
for (Class targetInterface : interfaces) {
clazzFirstLineContent += targetInterface.getSimpleName();
}
clazzFirstLineContent += "{" + line;
//设置固定私有属性InvocationHandler handler
String filedContent = tab + "private InvocationHandler handler;" + line;
//构造函数
String constructorContent = tab + "public $Proxy" + index + " (InvocationHandler handler){ this.handler = handler; }" + line;
String methodContent = "";
//遍历所有接口
for (Class targetInterface : interfaces) {
Method[] methods = targetInterface.getDeclaredMethods();
//实现所有接口的方法
for (Method method : methods) {
String returnTypeName = method.getReturnType().getSimpleName();
String methodName = method.getName();
Class args[] = method.getParameterTypes();
String argsContent = null;
String argsClassContent = null;
String paramsContent = null;
int flag = 0;
for (Class arg : args) {
if (argsContent == null) {
argsContent = "";
}
if (argsClassContent == null) {
argsClassContent = "";
}
if (paramsContent == null) {
paramsContent = "";
}
String argTypeName = arg.getSimpleName();
argsContent += argTypeName + " p" + flag + ",";
paramsContent += "p" + flag + ",";
argsClassContent += "p" + flag + ".getClass(),";
flag++;
}
paramsContent = StringUtils.isEmpty(paramsContent) ? "null" : paramsContent;
argsClassContent = StringUtils.isEmpty(argsClassContent) ? "null" : argsClassContent;
String oldArgsContent = argsContent;
argsContent = StringUtils.isEmpty(argsContent) ? "" : argsContent;
if (paramsContent != null && paramsContent.endsWith(",")) {
paramsContent = paramsContent.substring(0, paramsContent.length() - 1);
}
if (argsClassContent != null && argsClassContent.endsWith(",")) {
argsClassContent = argsClassContent.substring(0, argsClassContent.length() - 1);
}
if (argsContent != null && argsContent.endsWith(",")) {
argsContent = argsContent.substring(0, argsContent.length() - 1);
}
if ("void".equals(returnTypeName)) {
if (oldArgsContent == null) {
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {try{" + line
+ tab + tab + "handler.invoke(this,Class.forName(\"" + targetInterface.getName() + "\").getMethod(\"" + methodName + "\", " + paramsContent + ")," + paramsContent + ");" + line
+ tab + "}catch (Throwable var3) { var3.printStackTrace(); }" +
"}" + line;
} else {
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {try{" + line
+ tab + tab + "handler.invoke(this,Class.forName(\"" + targetInterface.getName() + "\").getMethod(\"" + methodName + "\", " + argsClassContent + "),new Object[]{" + paramsContent + "});" + line
+ tab + "}catch (Throwable var3) { var3.printStackTrace(); } " + line
+ tab + "}" + line;
}
} else {
if (oldArgsContent == null) {
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {try{" + line
+ tab + tab + "return ( " + returnTypeName + ") handler.invoke(this,Class.forName(\"" + targetInterface.getName() + "\").getMethod(\"" + methodName + "\", " + paramsContent + ")," + paramsContent + ");" + line
+ tab + "}catch (Throwable var3) { var3.printStackTrace(); }"
+ tab + "return null;}" + line;
} else {
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsContent + ") {try{" + line
+ tab + tab + "return (" + returnTypeName + ")handler.invoke(this,Class.forName(\"" + targetInterface.getName() + "\").getMethod(\"" + methodName + "\", " + argsClassContent + "),new Object[]{" + paramsContent + "});" + line
+ tab + "}catch (Throwable var3) { var3.printStackTrace(); } " + line
+ tab + "return null;}" + line;
}
}
}
}
//拼装java类字符串
classContent = packageContent + importContent + clazzFirstLineContent + filedContent + constructorContent + methodContent + "}";
//生成一个临时文件放到本地磁盘中,要先确保文件夹存在,不然会报错
String diskName = targetackageName.replaceAll("\\.", "\\\\");
File file = new File("d:\\" + diskName + "\\$Proxy" + index + ".java");
try {
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(classContent);
fw.flush();
fw.close();
//编辑为.class
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(file);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//类加载去加载到jvm中
URL[] urls = new URL[]{new URL("file:D:\\\\")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass(targetackageName + ".$Proxy" + index);
//调用构造函数
Constructor constructor = clazz.getConstructor(InvocationHandler.class);
//生成代理类
proxy = constructor.newInstance(handler);
} catch (Exception e) {
}
return proxy;
}
}
InvocationHandler:
package com.yang.proxy.dynamicproxy.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* JDK动态代理
* 被代理类必须实现接口,因为Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承)
* <p>
* 就是你给我一个接口,我替你生成一个代理实现类。
* 为什么要传一个tag呢?完全可以不传的,只是因为你想使用它的方法去实现你的逻辑。
* 我们可以拿到returnType,自定义的返回一个同类型的值,但是你这创建这个值的逻辑(invoke中的逻辑,只有一个returnType你只能创建一个返回对象,但是你得set属性吧,这个set属性的逻辑)是定制化的,只能适用某个接口中的某一个方法的实现逻辑,不适用这个接口中的所有方法,更不适用所有接口的所有方法。
* 所以最好的办法就是我们拿到接口的一个已有的实现类去执行它里面的每一个对应接口的实现方法
* </p>
* Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效
*
* @author tona.sun
* @date 2019/8/17 17:11
*/
public class MyJdkInvocationHandler implements InvocationHandler {
private Object tag;
public MyJdkInvocationHandler(Object tag) {
this.tag = tag;
}
//被代理方法其实执行的是这个方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// System.out.println("invoke proxy:" + proxy);
/*Class<?> returnType = method.getReturnType();
if ("void".equals(returnType.getName())) {
return null;
}*/
try {
//执行的是tag中的method,因为method是用tag获取的,所以只能用tag去执行
//后来我改成了method用接口去获取,这样就能用proxy去执行了,然后不出所料的发生了内存溢出(循环调用,死循环了)
//Object invoke = method.invoke(proxy, args);
Object invoke = method.invoke(tag, args);
return invoke;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}catch (Throwable e){
e.printStackTrace();
}
return null;
}
}