jdk动态代理实现原理

简介: jdk动态代理实现原理

为什么叫动态代理,个人理解是代理的类是在运行时动态生成的,


开门见山,lets go..


java中可以通过jdk提供的 Proxy.newProxyInstance静态方法来创建动态代理对象,下面先来看看这个方法的实现

 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
            throws IllegalArgumentException {
        //InvocationHandler不能为空,因为对代理对象的所有方法调用实际上都会委托到InvocationHandler的invoke方法,
        //这个我们后面通过查看产生的代理类的源代码便会一目了然
        if (h == null) {
            throw new NullPointerException();
        }
        //这个是核心的地方,通过提供的ClassLoader和interface列表来产生代理类,具体的实现可以参考getProxyClass这个方法的实现,
        //真正的工作是由sun.misc.ProxyGenerator这个类来完成的,可以google查看具体的逻辑.在我们的程序中通过设置
        //System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以查看产生的类文件
        Class cl = getProxyClass(loader, interfaces);
        //因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例
        //创建代理对象
        try {
            Constructor cons = cl.getConstructor(constructorParams);
            return (Object) cons.newInstance(new Object[] { h });
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString());
        } catch (IllegalAccessException e) {
            throw new InternalError(e.toString());
        } catch (InstantiationException e) {
            throw new InternalError(e.toString());
        } catch (InvocationTargetException e) {
            throw new InternalError(e.toString());
        }
    }

下面通过个例子来说明下:

先来定义一个接口,jdk的动态代理基于接口来创建代理类,不能基于类的原因是java不支持多重继承,而代理类都会继承Proxy类(个人理解).

/**
 * Subject
 * 
 * @author Kevin Fan
 * @since 2013-9-13 下午2:43:33
 */
public interface Subject {
    void pub(String key, String content);
    String sub(String key);
}


再来一个具体的实现,在代理模式中可以叫它的实例可以叫target,这个是真正执行操作的对象

/**
 * SimpleSubject
 * 
 * @author Kevin Fan
 * @since 2013-9-13 下午2:45:03
 */
public class SimpleSubject implements Subject {
    private Map<String, String> msg = new ConcurrentHashMap<String, String>();
    public void pub(String key, String content) {
        System.out.println("pub msg: key is " + key + ", content is " + content);
        msg.put(key, content);
    }
    public String sub(String key) {
        if (msg.containsKey(key)) {
            String ret = msg.get(key);
            System.out.println("sub msg: key is " + key + ", result is " + ret);
            return ret;
        }
        return null;
    }
}

好,接下来我们来写个动态代理工厂,根据 不同的target来创建动态代理对象

/**
 * SubjectProxyFactory
 * 
 * @author Kevin Fan
 * @since 2013-9-13 下午2:47:24
 */
public class SubjectProxyFactory {
    //TODO: cache 
    public static Subject getSubject(final Subject realSubject) {
        return (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), new Class[] { Subject.class },
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("\naction before method invocation....");
                        Object retVal = method.invoke(realSubject, args);
                        System.out.println("action after method invocation....\n");
                        return retVal;
                    }
                });
    }
}

可以看到这是一个简单的实现,只是在真实对象执行前后各打一句信息..



接下来用一个 main函数来把这些结合起来

  • =
/**
 * Demo
 * 
 * @author Kevin Fan
 * @since 2013-9-13 下午2:50:28
 */
public class Demo {
    public static void main(String[] args) {
        //设置此系统属性,以查看代理类文件
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //创建真实对象
        Subject subj = new SimpleSubject();
        subj.pub("name", "kevin.fan");
        subj.sub("name");
        //创建代理对象
        Subject proxy = SubjectProxyFactory.getSubject(subj);
        proxy.pub("hobby", "r&b music");
        proxy.sub("name");
    }
}


ok,小手抖一下,走你,看下执行结果

pub msg: key is name, content is kevin.fan
sub msg: key is name, result is kevin.fan
action before method invocation....
pub msg: key is hobby, content is r&b music
action after method invocation....
action before method invocation....
sub msg: key is name, result is kevin.fan
action after method invocation....


可以看到在调用代理对象的方法时,添加的额外动作已经生效,接下来我们看下生成的代理类的代码..

import com.aliyun.demo.kevin.coder.lang.proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//这里很清楚了,代理类继承了Proxy类,并且实现了Proxy.newProxyInstance这个方法中传入的接口
public final class $Proxy0 extends Proxy
  implements Subject
{
  //这些方法在下面的static init block中进行初始化
  private static Method m4;
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;
  static
  {
    try
    {
      m4 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("sub", new Class[] { Class.forName("java.lang.String") });
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("pub", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
  //构造函数,接收一个 InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里可以
  //通过InvocationHandler实例作为参数来反射获取Constructer实例 
  public $Proxy0 paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }
  //下面通过这个来看下代理对象中方法是怎样调用的
  public final String sub(String paramString)
    throws 
{
    try
    {
       //全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数
      return (String)this.h.invoke(this, m4, new Object[] { paramString });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  public final boolean equals(Object paramObject)
    throws 
{
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  public final void pub(String paramString1, String paramString2)
    throws 
{
    try
    {
      this.h.invoke(this, m3, new Object[] { paramString1, paramString2 });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  public final int hashCode()
    throws 
{
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  public final String toString()
    throws 
{
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
}


目录
相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
21天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
17 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
18 1
|
3月前
|
Java API 开发者
Jdk动态代理为啥不能代理Class?
该文章主要介绍了JDK动态代理的原理以及为何JDK动态代理不能代理Class。
Jdk动态代理为啥不能代理Class?
|
3月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
212 0
|
3月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
172 0
|
5月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
30 0
|
5月前
|
设计模式 Java 程序员
java动态代理(JDK和cglib)
java动态代理(JDK和cglib)
40 0
|
5月前
|
缓存 Java Maven
JDK 动态代理
JDK 动态代理
28 0
|
5月前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
59 0