动态代理 (JDK 动态代理)

小咪咪 2022-02-02 14:09 523阅读 0赞

动态代理 代理类在程序运行时被创建,这种代理方式称为动态代理

动态代理实现有两种方式,JDK 动态代理和 CGlib 动态代理,本文介绍JDK 动态代理

JDK 动态代理:创建动态代理类,实现 InvocationHandler 接口,重写 invoke 方法,在 invoke 方法中通过反射调用被代理类的方法,实现代理。jdk 动态代理只能代理接口,即只能代理接口的实现类

JDK 动态代理示例代码

定义一个接口

  1. package com.jdkdynamicproxy.service;
  2. public interface Subject {
  3. void proxyMethod();
  4. }

被代理类,实现接口

  1. package com.jdkdynamicproxy.service.impl;
  2. import com.jdkdynamicproxy.service.Subject;
  3. /**
  4. * 被代理类
  5. * @author Administrator
  6. */
  7. public class AgentTarget implements Subject {
  8. @Override
  9. public void proxyMethod() {
  10. System.out.println("被代理的方法执行了");
  11. }
  12. }

动态代理类,实现 InvocationHandler 接口

  1. package com.jdkdynamicproxy.jdkproxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import com.jdkdynamicproxy.service.impl.AgentTarget;
  5. /**
  6. * 动态代理类,实现 InvocationHandler接口
  7. * @author Administrator
  8. */
  9. public class JdkDynamicProxySubject implements InvocationHandler {
  10. private AgentTarget agentTarget;
  11. public JdkDynamicProxySubject(AgentTarget agentTarget) {
  12. this.agentTarget = agentTarget;
  13. }
  14. @Override
  15. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  16. //动态代理逻辑
  17. System.out.println("before");
  18. Object res = null;
  19. try {
  20. //用反射调用被代理类的方法
  21. res = method.invoke(agentTarget, args);
  22. }catch (Exception ex){
  23. System.out.println("ex:" + ex.getMessage());
  24. throw ex;
  25. }finally {
  26. System.out.println("after");
  27. }
  28. return res;
  29. }
  30. }

测试类

  1. package com.jdkdynamicproxy;
  2. import java.lang.reflect.Proxy;
  3. import com.jdkdynamicproxy.jdkproxy.JdkDynamicProxySubject;
  4. import com.jdkdynamicproxy.service.Subject;
  5. import com.jdkdynamicproxy.service.impl.AgentTarget;
  6. public class JdkDynamicProxyMain {
  7. public static void main(String[] args) {
  8. //配置系统属性sun.misc.ProxyGenerator.saveGeneratedFile为true,代理类生成时会自动将生成的代理类写入硬盘
  9. System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
  10. Subject subject = (Subject) Proxy.newProxyInstance(
  11. JdkDynamicProxyMain.class.getClassLoader(), //类加载器
  12. new Class[]{Subject.class} , //代理接口
  13. new JdkDynamicProxySubject(new AgentTarget()) //InvocationHandler对象
  14. );
  15. subject.proxyMethod();
  16. }
  17. }

运行如下

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70

程序运行后,在项目目录下生成了代理类的 class 文件

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzanp6Y2Jx_size_16_color_FFFFFF_t_70 1

对生成的 $Proxy0.class 文件进行反编译

  1. package com.sun.proxy;
  2. import com.jdkdynamicproxy.service.Subject;
  3. import java.lang.reflect.InvocationHandler;
  4. import java.lang.reflect.Method;
  5. import java.lang.reflect.Proxy;
  6. import java.lang.reflect.UndeclaredThrowableException;
  7. public final class $Proxy0 extends Proxy implements Subject {
  8. private static Method m1;
  9. private static Method m2;
  10. private static Method m3;
  11. private static Method m0;
  12. public $Proxy0(InvocationHandler var1) throws {
  13. super(var1);
  14. }
  15. public final boolean equals(Object var1) throws {
  16. try {
  17. return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  18. } catch (RuntimeException | Error var3) {
  19. throw var3;
  20. } catch (Throwable var4) {
  21. throw new UndeclaredThrowableException(var4);
  22. }
  23. }
  24. public final String toString() throws {
  25. try {
  26. return (String)super.h.invoke(this, m2, (Object[])null);
  27. } catch (RuntimeException | Error var2) {
  28. throw var2;
  29. } catch (Throwable var3) {
  30. throw new UndeclaredThrowableException(var3);
  31. }
  32. }
  33. public final void proxyMethod() throws {
  34. try {
  35. super.h.invoke(this, m3, (Object[])null);
  36. } catch (RuntimeException | Error var2) {
  37. throw var2;
  38. } catch (Throwable var3) {
  39. throw new UndeclaredThrowableException(var3);
  40. }
  41. }
  42. public final int hashCode() throws {
  43. try {
  44. return (Integer)super.h.invoke(this, m0, (Object[])null);
  45. } catch (RuntimeException | Error var2) {
  46. throw var2;
  47. } catch (Throwable var3) {
  48. throw new UndeclaredThrowableException(var3);
  49. }
  50. }
  51. static {
  52. try {
  53. m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  54. m2 = Class.forName("java.lang.Object").getMethod("toString");
  55. m3 = Class.forName("com.jdkdynamicproxy.service.Subject").getMethod("proxyMethod");
  56. m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  57. } catch (NoSuchMethodException var2) {
  58. throw new NoSuchMethodError(var2.getMessage());
  59. } catch (ClassNotFoundException var3) {
  60. throw new NoClassDefFoundError(var3.getMessage());
  61. }
  62. }
  63. }

可以看到生成的 $Proxy0.class 实现了 Subject 接口,重写 proxyMethod 方法。在重写的 proxyMethod 方法中,去调用 JdkDynamicProxySubject 的 invoke(Object proxy, Method method, Object[] args) 方法,实现代理

整个程序的运行流程:Proxy.newProxyInstance(JdkDynamicProxyMain.class.getClassLoader(), new Class[]{Subject.class} , new JdkDynamicProxySubject(new AgentTarget()) ) 创建对象 subject 时,生成了代理类 $Proxy0.class;subject 对象调用proxyMethod 方法时,proxyMethod 方法调用 JdkDynamicProxySubject 的 invoke 方法,invoke 方法中通过反射调用被代理方法,实现动态代理

发表评论

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

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

相关阅读

    相关 代理-jdk动态代理

    1、基于接口的实现,要jdk动态代理的类必须要实现一个接口; 2、中介类:实现了InvocationHandler,并重写这个接口的 方法(public Object inv

    相关 JDK动态代理和CGLib动态代理

        JDK 动态代理是 JVM 根据传进来的对象,动态的创建对象的代理对象并返回。     CGLib 动态代理比较复杂,它是通过继承的方式来实现类的代理。 JDK