实现步骤
1、生成代理类的源代码
2、将源代码保存到磁盘
3、使用JavaCompiler编译源代码生成.class字节码文件
4、使用JavaCompiler编译源代码生成.class字节码文件
5、返回代理类的实例
实现代码
package com.lnjecit.proxy.custom; import java.lang.reflect.Method; /** * 自定义InvocationHandler */ public interface MyInvocationHandler { /** * 执行代理实例中目标方法,并返回结果 * @param proxy 代理实例 * @param method 目标方法 * @param args 目标方法中的参数 * @return */ Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
package com.lnjecit.proxy.custom; import java.io.File; import java.lang.reflect.Constructor; /** * 自定义代理类 * * @author * @create 2018-04-08 21:55 **/ public class MyProxy { /** * 生成代理类实例 * * @param classLoader 类加载器 * @param interfaces 被代理类实现的接口数组 * @param h * @return */ public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h) throws ClassNotFoundException { // 1、生成代理类的源代码 String sourceFileStr = MyProxyGenerator.generateSourceFile("$Proxy0", interfaces); String filePath = MyProxy.class.getResource("/").getPath(); try { // 2、将源代码保存到磁盘 File sourceFile = MyProxyGenerator.saveGeneratedSourceFile(filePath, sourceFileStr); // 3、使用JavaCompiler编译源代码生成.class字节码文件 MyProxyGenerator.generateProxyClass(sourceFile); // 4、使用ClassLoader将.class文件中的内容加载到JVM Class proxyClass = classLoader.findClass("$Proxy0"); // 5、返回代理类的实例 Constructor c = proxyClass.getConstructor(MyInvocationHandler.class); // 删除生成的源文件 // sourceFile.delete(); return c.newInstance(h); } catch (Exception e) { e.printStackTrace(); } return null; } }
package com.lnjecit.proxy.custom; import javax.tools.*; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Method; /** * 生成代理类 * * @author * @create 2018-04-08 22:01 **/ public class MyProxyGenerator { private static final String PROXY_PACKAGE = "com.lnjecit.proxy.custom"; private static final String LINE_FEED = " "; /** * 生成代理类的源代码 * @param proxyName * @param interfaces * @return */ public static String generateSourceFile(String proxyName, Class<?>[] interfaces) { StringBuffer buffer = new StringBuffer(); buffer.append("package " + PROXY_PACKAGE + ";" + LINE_FEED); for (Class<?> intf : interfaces) { buffer.append("import " + intf.getName() + ";" + LINE_FEED); } buffer.append("import java.lang.reflect.Method;" + LINE_FEED); buffer.append("import com.lnjecit.proxy.custom.MyProxy;" + LINE_FEED); buffer.append("import com.lnjecit.proxy.custom.MyInvocationHandler;" + LINE_FEED); buffer.append("public final class " + proxyName + " extends MyProxy implements "); for (Class<?> intf : interfaces) { buffer.append(intf.getSimpleName()); } buffer.append("{" + LINE_FEED); buffer.append("private MyInvocationHandler h;" + LINE_FEED); // 构造函数 buffer.append("public " + proxyName + "(MyInvocationHandler h" + ") {" + LINE_FEED); buffer.append("this.h = h;" + LINE_FEED); buffer.append("}" + LINE_FEED); for (Class<?> intf : interfaces) { Method[] methods = intf.getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; buffer.append("public " + method.getReturnType() + " " + method.getName() + "()" + "{" + LINE_FEED); buffer.append("try {" + LINE_FEED); buffer.append("Method m = " + intf.getName() + ".class.getMethod("" + method.getName() + "",new Class[]{});" + LINE_FEED); buffer.append("h.invoke(this, m, null);" + LINE_FEED); buffer.append("} catch (Throwable e) {" + LINE_FEED); buffer.append("e.printStackTrace();" + LINE_FEED); buffer.append("}" + LINE_FEED); buffer.append("}" + LINE_FEED); } } buffer.append("}" + LINE_FEED); return buffer.toString(); } /** * 将代理类源文件便以为.class文件 * @param sourceFile 源文件 * @throws IOException */ public static void generateProxyClass(File sourceFile) throws IOException { // 获取JavaCompiler JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // DiagnosticListener用于获取Diagnostic信息,Diagnostic信息包括:错误,警告和说明性信息 DiagnosticListener<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); // StandardJavaFileManager:用于管理与工具有关的所有文件 StandardJavaFileManager manager = compiler.getStandardFileManager(diagnostics, null, null); // avaFileObjects: 是java源码文件(.java)和class文件(.class)的抽象 Iterable iterable = manager.getJavaFileObjects(sourceFile); // 编译任务 JavaCompiler.CompilationTask task = compiler.getTask(null, manager, diagnostics, null, null, iterable); task.call(); manager.close(); } /** * 将代理类的源代码保存到本地磁盘 * @param filePath 文件保存路径 * @param sourceFileStr 源代码 * @throws IOException */ public static File saveGeneratedSourceFile(String filePath, String sourceFileStr) throws IOException { File sourceFile = new File(filePath + PROXY_PACKAGE.replaceAll("\.", "/") + "/" + "$Proxy0.java"); FileWriter fw = new FileWriter(sourceFile); fw.write(sourceFileStr); fw.flush(); fw.close(); return sourceFile; } }
package com.lnjecit.proxy.custom; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * 自定义ClassLoader * @author * @create 2018-04-08 21:57 **/ public class MyClassLoader extends ClassLoader { private File baseDir; public MyClassLoader(){ String basePath = MyClassLoader.class.getResource("").getPath(); this.baseDir = new java.io.File(basePath); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String className = MyClassLoader.class.getPackage().getName() + "." + name; if(baseDir != null){ File classFile = new File(baseDir,name.replaceAll("\.", "/") + ".class"); if(classFile.exists()){ FileInputStream in = null; ByteArrayOutputStream out = null; try{ in = new FileInputStream(classFile); 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{ if(null != in){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != out){ try { out.close(); } catch (IOException e) { e.printStackTrace(); } } classFile.delete(); } } } return null; } }
package com.lnjecit.proxy.custom; import java.lang.reflect.Method; /** * @author * @create 2018-04-08 21:59 **/ public class JDKDynamicProxy implements MyInvocationHandler { Object target; public <T> T getInstance(Object target) throws Exception { this.target = target; return (T) MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before invoke"); Object result = method.invoke(target, args); System.out.println("After invoke"); return result; } }
测试代码
package com.lnjecit.proxy; /** * Subject * 抽象主题接口 * @author * @create 2018-03-29 14:16 **/ public interface Subject { void doSomething(); }
package com.lnjecit.proxy; /** * RealSubject * 真实主题类 * @author * @create 2018-03-29 14:21 **/ public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something"); } }
import com.lnjecit.proxy.RealSubject; import com.lnjecit.proxy.Subject; /** * 测试类 * @author * @create 2018-04-08 23:07 **/ public class Client { public static void main(String[] args) { try { Subject subject = new JDKDynamicProxy().getInstance(new RealSubject()); subject.doSomething(); } catch (Exception e) { e.printStackTrace(); } } }
测试结果:
Before invoke
RealSubject do something
After invoke
在调试过程中可看到:在classpath路径下生成了$Proxy0.java和$Proxy0.class两个文件
以上仅仅实现了代理一个接口并且方法无参数的简单代理,只是为了更好理解jdk动态代理。