手写JDK动态代理

小鱼儿 2022-05-25 12:24 238阅读 0赞

一,JDK动态代理

  1. 在纯手写动态代理前,首先分析一套标准JDK动态代理的执行流程。

1,目标类顶层接口

  1. public interface ProxyInterface {
  2. public void targetMethod();
  3. }

2,目标类

  1. public class JDKProxyTarget implements ProxyInterface{
  2. @Override
  3. public void targetMethod() {
  4. System.out.println("代理方法...");
  5. }
  6. }

3,代理类

  1. public class JDKProxy {
  2. private ProxyInterface proxyInterface;
  3. public JDKProxy(ProxyInterface proxyInterface) {
  4. this.proxyInterface = proxyInterface;
  5. }
  6. public Object instanceProxy() {
  7. System.out.println("代理方法开始...");
  8. ProxyInterface instance = (ProxyInterface) Proxy.newProxyInstance(
  9. proxyInterface.getClass().getClassLoader(),
  10. proxyInterface.getClass().getInterfaces(),
  11. new InvocationHandler() {
  12. @Override
  13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14. method.invoke(proxyInterface, args);
  15. System.out.println("代理方法结束...");
  16. return null;
  17. }
  18. });
  19. return instance;
  20. }
  21. }

4,测试类

  1. public class JDKProxyTest {
  2. public static void main(String[] args) throws Exception {
  3. JDKProxy proxy = new JDKProxy(new JDKProxyTarget());
  4. ProxyInterface proxyInterface = (ProxyInterface) proxy.instanceProxy();
  5. System.out.println(proxyInterface.getClass());
  6. proxyInterface.targetMethod();
  7. }
  8. }

70

5,代码解析

  1. aProxy.newInstance()方法
  2. \* 第一个参数为目标类的类加载器
  3. \* 第二个参数为目标类的接口集合,JDK动态代理目标类必须实现一个接口,这是为了保证生成的代理类和目标类之前的强一致性关系
  4. \* 第三个参数为InvocationHandler接口的实现类,这里直接通过匿名内部类实现,重写了invoke方法
  5. bInvocationHandler接口实现类
  6. \* 实现该类必须重写invoke()方法,动态代理实现在代理类中该接口的实现类调用该方法,并在该方法中反射执行该方法完成整个动态代理流程;
  7. \* 第一个参数为生成的动态代理对象;
  8. \* 第二个参数为动态代理在客户端执行的方法;
  9. \* 第三个参数为该方法的参数列表;
  10. \* 通过反射来完成方法调用;
  11. c,通过a步骤后,JDK会虚拟生成一个$Proxy0类,该类也实现了目标类实现的接口,从而多态返回该虚拟类对象,可以通过代码输出该类
  12. \* 代码
  13. public class JDKProxyTest {
  14. public static void main(String[] args) throws Exception {
  15. JDKProxy proxy = new JDKProxy(new JDKProxyTarget());
  16. ProxyInterface proxyInterface = (ProxyInterface) proxy.instanceProxy();
  17. System.out.println(proxyInterface.getClass());
  18. proxyInterface.targetMethod();
  19. byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{ProxyInterface.class});
  20. FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
  21. outputStream.write(bytes);
  22. outputStream.close();
  23. }
  24. }
  25. \* $Proxy0 --- 生成为.class文件,直接通过IDEA进行反编译

70 1

  1. public final class $Proxy0 extends Proxy implements ProxyInterface {
  2. private static Method m1;
  3. private static Method m2;
  4. private static Method m3;
  5. private static Method m0;
  6. public $Proxy0(InvocationHandler var1) throws {
  7. super(var1);
  8. }
  9. public final boolean equals(Object var1) throws {
  10. try {
  11. return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
  12. } catch (RuntimeException | Error var3) {
  13. throw var3;
  14. } catch (Throwable var4) {
  15. throw new UndeclaredThrowableException(var4);
  16. }
  17. }
  18. public final String toString() throws {
  19. try {
  20. return (String)super.h.invoke(this, m2, (Object[])null);
  21. } catch (RuntimeException | Error var2) {
  22. throw var2;
  23. } catch (Throwable var3) {
  24. throw new UndeclaredThrowableException(var3);
  25. }
  26. }
  27. public final void targetMethod() throws {
  28. try {
  29. super.h.invoke(this, m3, (Object[])null);
  30. } catch (RuntimeException | Error var2) {
  31. throw var2;
  32. } catch (Throwable var3) {
  33. throw new UndeclaredThrowableException(var3);
  34. }
  35. }
  36. public final int hashCode() throws {
  37. try {
  38. return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
  39. } catch (RuntimeException | Error var2) {
  40. throw var2;
  41. } catch (Throwable var3) {
  42. throw new UndeclaredThrowableException(var3);
  43. }
  44. }
  45. static {
  46. try {
  47. m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
  48. m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  49. m3 = Class.forName("com.gupao.designpattern.proxy.jdk.ProxyInterface").getMethod("targetMethod", new Class[0]);
  50. m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  51. } catch (NoSuchMethodException var2) {
  52. throw new NoSuchMethodError(var2.getMessage());
  53. } catch (ClassNotFoundException var3) {
  54. throw new NoClassDefFoundError(var3.getMessage());
  55. }
  56. }
  57. }
  58. d 可以看到该虚拟类继承Proxy类并实现了目标类顶层接口,并反射获取了目标类中的所有方法的Method对象;
  59. e 同时,虚拟类也同时重写了目标类的所有方法,并通过下列方式进行调用
  60. super.h.invoke(this, m3, (Object[])null);
  61. super 指该代理类的超类,也就是Proxy
  62. h 点进源码可以看到这样一行声明
  63. protected InvocationHandler h;

在虚拟类的构造器中,也获取了InvocationHandler的引用,所以,这里的h,指的也就是在匿名内部类定义的实现类对象;

  1. h.invoke():就是调用匿名内部类中重写的invoke()方法,分别传递参数该对象(this),执行的方法(method),方法参数(null);

二,手写动态代理步骤分析

  1. 从上面标准的JDK动态流程可以看出,手写动态代理,需要这样几个类
  2. 1SelfProxy类,定义newInstance()方法,进行代理对象创建
  3. \* 在该方法中首先需要输出代理类的.java文件
  4. \* 编译该.java文件生成.class文件
  5. \* 通过类加载器加载该.class文件
  6. \* 生成该.class文件的事例对象作为代理对象返回
  7. 2SelfInvocationHandler接口,定义invoke()方法,在代理类中进行目标方法调用
  8. \* 在.java文件中,定义构造器,传递该类引用
  9. \* 通过SelfInvocationHandler实现类对象调用invoke()方法,实现代理方式的方法调用
  10. 3SelfClassloader,自定义类加载器,继承JDKClassLoader类,实现自定义的加载方式
  11. 4SelfJDKProxy,实现SelfInvocationHandler接口,重写invoke()方法,实现最终方法运行

三,手写动态代理代码实现

1,目标类顶层接口

  1. public interface SelfProxyInterface {
  2. public void targetMethod();
  3. }

2,目标类

  1. public class SelfJDKProxyTarget implements SelfProxyInterface{
  2. @Override
  3. public void targetMethod() {
  4. System.out.println("代理方法...");
  5. }
  6. }

3,SelfClassLoader类 — 自定义类加载器,加载.class到JVM内存中

  1. public class SelfClassLoader extends ClassLoader{
  2. private File classPathFile;
  3. public SelfClassLoader() {
  4. String classPath = SelfClassLoader.class.getResource("").getPath();
  5. this.classPathFile = new File(classPath);
  6. }
  7. @Override
  8. protected Class<?> findClass(String name) throws ClassNotFoundException {
  9. String className = SelfClassLoader.class.getPackage().getName() + "." + name;
  10. if (null != classPathFile) {
  11. File classFile = new File(classPathFile, name + ".class");
  12. if (classFile.exists()) {
  13. FileInputStream in = null;
  14. ByteArrayOutputStream out = null;
  15. try {
  16. in = new FileInputStream(classFile);
  17. out = new ByteArrayOutputStream();
  18. byte[] bytes = new byte[1024];
  19. int len;
  20. while((len = in.read(bytes)) != -1) {
  21. out.write(bytes, 0, len);
  22. }
  23. return defineClass(className, out.toByteArray(), 0, out.size());
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. } finally {
  27. try {
  28. if (null != in) {
  29. in.close();
  30. }
  31. if (null != out) {
  32. out.close();
  33. }
  34. } catch (Exception e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  39. }
  40. return null;
  41. }
  42. }

4,SelfProxy类 — 生成虚拟代理类,创建代理对象

  1. public class SelfProxy {
  2. private static final String ENTER = "\r\n";
  3. public static Object newInstance(SelfClassLoader classLoader, Class<?>[] interfaces, SelfInvocationHandler h) {
  4. try {
  5. // 动态生成源代码
  6. String srcClass = generateSrc(interfaces);
  7. // 输出Java文件
  8. String filePath = SelfProxy.class.getResource("").getPath() + "$ProxyO.java";
  9. System.out.println(filePath);
  10. FileWriter fileWriter = new FileWriter(filePath);
  11. fileWriter.write(srcClass);
  12. fileWriter.flush();
  13. fileWriter.close();
  14. // 编译Java文件为class文件
  15. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  16. StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
  17. Iterable iterable = fileManager.getJavaFileObjects(filePath);
  18. JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
  19. task.call();
  20. fileManager.close();
  21. // 加载编译生成的class文件到JVM
  22. Class<?> proxyClass = classLoader.findClass("$ProxyO");
  23. Constructor<?> constructor = proxyClass.getConstructor(SelfInvocationHandler.class);
  24. // 删掉虚拟代理类
  25. File file = new File(filePath);
  26. file.delete();
  27. // 返回字节码重组以后的代理对象
  28. return constructor.newInstance(h);
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. return null;
  33. }
  34. private static String generateSrc(Class<?>[] interfaces) {
  35. StringBuilder stringBuilder = new StringBuilder();
  36. stringBuilder.append("package com.gupao.designpattern.proxy.self;" + ENTER + ENTER);
  37. stringBuilder.append("import com.gupao.designpattern.proxy.jdk.ProxyInterface;" + ENTER);
  38. stringBuilder.append("import java.lang.reflect.Method;" + ENTER);
  39. stringBuilder.append("public class $ProxyO implements " + interfaces[0].getName() + "{" + ENTER);
  40. stringBuilder.append("SelfInvocationHandler h;" + ENTER);
  41. stringBuilder.append("public $ProxyO(SelfInvocationHandler h) {" + ENTER);
  42. stringBuilder.append("this.h = h;" + ENTER);
  43. stringBuilder.append("}" + ENTER);
  44. for (Method method : interfaces[0].getMethods()) {
  45. stringBuilder.append("public " + method.getReturnType().getName() + " " + method.getName() + "() {" + ENTER);
  46. stringBuilder.append("try {" + ENTER);
  47. stringBuilder.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{});" + ENTER);
  48. stringBuilder.append("this.h.invoke(this, m, null);" + ENTER);
  49. stringBuilder.append("} catch(Throwable able) {" + ENTER);
  50. stringBuilder.append("able.getMessage();" + ENTER);
  51. stringBuilder.append("}" + ENTER);
  52. stringBuilder.append("}" + ENTER + ENTER);
  53. }
  54. stringBuilder.append("}" + ENTER);
  55. return stringBuilder.toString();
  56. }
  57. }
  58. 该类代码的具体步骤在注释中已经写明;

5,查看生成的.java文件

  1. package com.gupao.designpattern.proxy.self;
  2. import com.gupao.designpattern.proxy.jdk.ProxyInterface;
  3. import java.lang.reflect.Method;
  4. public class $ProxyO implements com.gupao.designpattern.proxy.self.SelfProxyInterface {
  5. SelfInvocationHandler h;
  6. public $ProxyO(SelfInvocationHandler h) {
  7. this.h = h;
  8. }
  9. public void targetMethod() {
  10. try {
  11. Method m = com.gupao.designpattern.proxy.self.SelfProxyInterface.class.getMethod("targetMethod", new Class[]{});
  12. this.h.invoke(this, m, null);
  13. } catch (Throwable able) {
  14. able.getMessage();
  15. }
  16. }
  17. }

6,查看生成的.class文件

  1. package com.gupao.designpattern.proxy.self;
  2. import java.lang.reflect.Method;
  3. public class $ProxyO implements SelfProxyInterface {
  4. SelfInvocationHandler h;
  5. public $ProxyO(SelfInvocationHandler var1) {
  6. this.h = var1;
  7. }
  8. public void targetMethod() {
  9. try {
  10. Method var1 = SelfProxyInterface.class.getMethod("targetMethod", new Class[0]);
  11. this.h.invoke(this, var1, (Object[])null);
  12. } catch (Throwable var2) {
  13. var2.getMessage();
  14. }
  15. }
  16. }

7,SelfInvocationHandler接口,定义invoke()方法

  1. public interface SelfInvocationHandler {
  2. public Object invoke(Object proxy, Method method, Object[] args);
  3. }

8,SelfJdkProxy,定义newInstance()方法创建代理对象,并实现InvocationHandler接口,重写invoke()方法,通过反射实现方法最终运行

  1. public class SelfJDKProxy implements SelfInvocationHandler{
  2. private SelfProxyInterface proxyInterface;
  3. public SelfJDKProxy(SelfProxyInterface proxyInterface) {
  4. this.proxyInterface = proxyInterface;
  5. }
  6. public Object instanceProxy() {
  7. System.out.println("代理方法开始...");
  8. SelfProxyInterface instance = (SelfProxyInterface) SelfProxy.newInstance(
  9. new SelfClassLoader(),
  10. proxyInterface.getClass().getInterfaces(), this);
  11. return instance;
  12. }
  13. @Override
  14. public Object invoke(Object proxy, Method method, Object[] args) {
  15. try {
  16. method.invoke(proxyInterface, args);
  17. System.out.println("代理方法结束...");
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. return null;
  22. }
  23. }

9,客户端执行

  1. public class SelfTest {
  2. public static void main(String[] args) {
  3. SelfJDKProxy proxy = new SelfJDKProxy(new SelfJDKProxyTarget());
  4. SelfProxyInterface proxyInterface = (SelfProxyInterface) proxy.instanceProxy();
  5. System.out.println(proxyInterface);
  6. proxyInterface.targetMethod();
  7. }
  8. }

70 2

10,总结

  1. 整个手写动态代理以说明问题为目的,整个流程中所有环境创建都是按照最简单方式在运行,旨在熟悉整个JDK动态代理的执行流程和底层实现;

发表评论

表情:
评论列表 (有 0 条评论,238人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JDK动态代理

    一,JDK动态代理     在纯手写动态代理前,首先分析一套标准JDK动态代理的执行流程。 1,目标类顶层接口 public interface ProxyInt

    相关 jdk动态代理

    之前的文章讲了动态代理的实现原理,这里我们来手写一下jdk的动态代理(支持实现多接口和带参数的方法)。主要原理就是生成一个和实现目标对象相同接口的一个代理对象,我们调用方法的时

    相关 Java动态代理

    如图1所示,动态代理的使用 这篇文章讲解动态代理的原理,以及如何手写动态代理。 以下是有关动态代理的使用,这是JDK默认帮我们实现的动态代理。 public