实现功能
- 通过Proxy的newProxyInstance返回代理对象
实现步骤
- 根据提供的接口类动态拼接字符串源码(动态产生代理)
- 将生成的字符串源码,调用提供的JDK Compiler API编译源码,产生新的类(代理类)
- 将动态产生的代理类load到内存当中,产生一个新的对象(代理对象)
- return 产生的代理对象
代码实现
-
InvocationHandler
public interface InvocationHandler { Object invoke(Object proxy, Method method) throws Exception; } -
Proxy
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.lang.reflect.Parameter; import java.net.URL; import java.net.URLClassLoader; /** * 模拟动态代理 */ public class Proxy { /** * 获取换行符 */ private static final String rt = System.lineSeparator(); /** * 动态代理类名 */ private static final String proxyClassName = "$Proxy0"; /** * 动态代理类保存路径 */ private static final String proxyClassFilePath = "f:/temp/proxy/"; public static Object newProxyInstance(Class infc, InvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //根据接口拼接字符串源代码 String methodStr = getMethodStr(infc); String str = "package cn.tswine.dp.proxy.imitation;" + rt + "import java.lang.reflect.Method;" + rt + rt + "public class " + proxyClassName + " implements " + infc.getName() + "{" + rt + " cn.tswine.dp.proxy.imitation.InvocationHandler h;" + rt + " public " + proxyClassName + "(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + methodStr + "}"; //将源码写入文件类 String fileName = proxyClassFilePath + proxyClassName + ".java"; File file = new File(fileName); FileWriter fw = new FileWriter(file); fw.write(str); fw.flush(); fw.close(); //编译源码(JDK Compiler API),产生新的类(代理类) JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(fileName); JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units); t.call(); fileMgr.close(); //将代理类load到内存当中,产生一个新的对象(代理对象) URL[] urls = new URL[]{new URL("file:/"+proxyClassFilePath)}; URLClassLoader ul = new URLClassLoader(urls); Class clazz = ul.loadClass("cn.tswine.dp.proxy.imitation.$Proxy0" ); //return 生成的代理对象 Constructor ctr = clazz.getConstructor(InvocationHandler.class); Object proxy = ctr.newInstance(h); return proxy; } /** * 获取方法字符串 * * @param infc 接口 * @return * @desc 未考虑导入外部包的情况, 未考虑参数问题 */ private static String getMethodStr(Class infc) { //获取接口的所有方法 Method[] methods = infc.getMethods(); StringBuilder sbMethod = new StringBuilder(); for (Method method : methods) { String returnType = method.getReturnType().getTypeName(); boolean returnFlag = returnType.equalsIgnoreCase("void") ? false : true; sbMethod.append("@Override"); sbMethod.append(rt); sbMethod.append("public " + returnType + " " + method.getName() + getMethodParams(method) + " {" + rt); sbMethod.append(" try {" + rt); sbMethod.append(" Method md = " + infc.getName() + ".class.getMethod(\"" + method.getName() + "\");" + rt); if (!returnFlag) { sbMethod.append(" h.invoke(this, md);" + rt); } else { sbMethod.append(" return (" + returnType + ")h.invoke(this, md);" + rt); } sbMethod.append(" }catch(Exception e) {e.printStackTrace();}" + rt); if (returnFlag) { sbMethod.append(" return null;" + rt); } sbMethod.append("}" + rt); } return sbMethod.toString(); } /** * 获取方法参数 * * @param method * @return */ private static String getMethodParams(Method method) { StringBuilder sb = new StringBuilder(); Parameter[] parameters = method.getParameters(); sb.append("("); if (parameters != null && parameters.length > 0) { for (int i = 0; i < parameters.length; i++) { Parameter parameter = parameters[i]; sb.append(parameter.getType().getName() + " "); sb.append(parameter.getName()); if ((i + 1) < parameters.length) { sb.append(","); } } } sb.append(")"); return sb.toString(); } }
客户端使用
- TimeInvocationHandler
public class TimeInvocationHandler implements InvocationHandler { private Object target; public TimeInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method) throws Exception { long start = System.currentTimeMillis(); Object invoke = method.invoke(target); long end = System.currentTimeMillis(); System.out.println("request time :" + (end - start)); return invoke; } } - Client
public class Client { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { RealHttpApi realHttpApi = new RealHttpApi(); InvocationHandler invocationHandler = new TimeInvocationHandler(realHttpApi); HttpApi2 proxy = (HttpApi2) Proxy.newProxyInstance(HttpApi2.class, invocationHandler); String response = proxy.request(); System.out.println("response:" + response); } }