深入理解java虚拟机(14):手写动态生成一个代理类
通过java动态生成一个代理类的代码如下
package aop.proxyutil;
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.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.net.URLClassLoader;
/**
* @author: yangchun
* @description:
* @date: Created in 2019-09-24 16:09
*/
public class ProxyUtil {
/**
* .java
* .class
* .new
* @return
*/
public static Object newInstance(Class targeInf, CustomInvocationHandler h) throws NoSuchMethodException{
Object proxy=null;
String infName = targeInf.getSimpleName();
String line ="\n";
String tab = "\t";
Method[] methods=targeInf.getMethods();
String content ="";
String packageContent = "package aop.proxyutil;"+line;
String importContent = "import "+targeInf.getName()+";"+line
+"import java.lang.reflect.Method;"+line
+"import java.lang.reflect.Parameter;"+line;
String clazzFirstLineContent = "public class $Proxy implements " +infName +" {"+line;
String fieldContent = tab+"private CustomInvocationHandler h;"+line;
String constructContent = tab+"public $Proxy(CustomInvocationHandler h){"+line
+tab+tab+"this.h = h;"+line+
tab+"}"+line;
String methodContent ="";
for(Method method:methods){
String returnType=method.getReturnType().getSimpleName();
String methodName = method.getName();
Class<?>[] paramsTypes= method.getParameterTypes();
Class[] args = method.getParameterTypes();
String argsContent ="";
String paramContent ="";
String param ="";
int flag =0;
for(Class arg:args){
String temp = arg.getSimpleName();
argsContent += temp +" p"+ flag+",";
paramContent += arg.getTypeName()+".class,";
param +="p"+flag+",";
flag++;
}
if(argsContent.length()>0){
argsContent = argsContent.substring(0,argsContent.lastIndexOf(","));
paramContent = paramContent.substring(0,paramContent.lastIndexOf(","));
param = param.substring(0,param.lastIndexOf(","));
}
methodContent+=tab+"public "+returnType+" "+methodName+"("+argsContent+"){"+line+
tab+tab+"try{"+line+
tab+tab+tab+"Method method = Class.forName(\""+targeInf.getName()+"\").getDeclaredMethod(\""+methodName+"\","+paramContent+");"+line;
//tab+tab+tab+"Parameter[] parameters=method.getParameters();"+line;
if(returnType.equals("void")){
methodContent +=tab+tab+tab+"h.invoke(method,"+param+");"+line+
tab+tab+"}"+"catch(Exception e){"+line+
tab+tab+tab+"e.printStackTrace();"+line+
tab+tab+"}"+line+
tab+"}";
}else {
methodContent +=tab+tab+"return h.invoke(method,parameters);"+line+
tab+"}"+line;
}
}
content = packageContent+importContent+clazzFirstLineContent+fieldContent+constructContent+methodContent+line+"}";
File file = new File("e:/backup/chubao/chubao/java/src/aop/proxyutil/$Proxy.java");
try {
if(!file.exists()){
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.flush();
fw.close();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
Iterable units = fileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask t = compiler.getTask(null,fileManager,null,null,null,units);
t.call();
fileManager.close();
URL[] urls = new URL[]{new URL("file:E:/backup/chubao/chubao/java/src/")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass("aop.proxyutil.$Proxy");
Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
proxy = constructor.newInstance(h);
}catch (Exception e){
e.printStackTrace();
}
return proxy;
}
}
测试代码如下
package aop.proxy;
import aop.proxyutil.ProxyUtil;
import aop.proxyutil.TestCustomInvocationHandler;
/**
* @author: yangchun
* @description:
* @date: Created in 2019-09-24 13:25
*/
public class Test {
public static void main(String[] args)throws Exception{
UserDaoImpl userDao = new UserDaoLogImpl();
// userDao.query();
UserDaoImpl $proxy =(UserDaoImpl) ProxyUtil.newInstance(UserDaoImpl.class,new TestCustomInvocationHandler(userDao));
// UserDaoImpl $proxy =new $Proxy(new TestCustomInvocationHandler(userDao));
$proxy.query(1);
}
}