动态代理原理分析

本文深入探讨了Java动态代理的概念,通过匿名类和动态代理两种方式创建接口实例。在MyBatis中,Mapper接口通过动态代理实现,允许我们在不修改原有代码的情况下扩展功能。文中通过示例展示了如何使用Proxy类生成代理对象,并解释了动态代理类的内部工作原理,包括InvocationHandler接口的invoke方法和生成的代理类源码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在研究mybaits的源码,mapper是接口,就是用的动态代理返回的代理对象;

必须记录一下,今天终于整明白动态代理了,也希望看到这篇文章的小伙伴们能够明白

接口是不能实例化的

如果我们要实例化的话 必须实现该接口,有个实现类才得行!!

1.使用匿名类的方式

public class TestProxy1 {
    interface UserMapper{
        void getUser();
    }
    public static void main(String[] args) {
            UserMapper userMapper = new UserMapper() {
                public void getUser() {
                    System.out.println("使用匿名类的方法");
                }
            };
    }
}

2.使用动态代理的方式

 //2.动态代理:第一个参数:类加载器 第二个参数:需要代理的接口 第三个参数:InvocationHandler的实现类
        UserMapper o = (UserMapper)Proxy.newProxyInstance(TestProxy1.class.getClassLoader(), new Class<?>[]{UserMapper.class}, new InvocationHandler() {
            //Method: 调用的方法  args:方法里面的参数值
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method+"----"+args[0]);
                return null;
            }
        });
 //通过代理对象调用方法
       o.getUser(12);

输出结果:

可以看到,我们代理成功了!!!!

 分析动态代理

不知道大家能否明白

下面是我的拙见,有什么不对的欢迎指出 

jdk帮我们底层帮我们动态的创建了一个实现类/代理类嘛:

Class<?> cl = getProxyClass0(loader, intfs);

通过构造方法创建对象,传入handler

cons.newInstance(new Object[]{h});

动态生成的代理类实现了接口,这也就是为啥我们可以通过代理对象调用相关的方法,下面可以查看生成的代理类信息

实现类里面可以通过反射获取到方法Method,

在实现方法的时候其实调用的是InvocationHandler的invoke方法,

然后传入Method,args,在我们的invokeHandler里面就是让我们用户去实现的具体要执行的操作

看一下为我们生成的代理类

帮我们创建了一个代理类

public final class $Proxy0 extends Proxy
  implements TestProxy1.UserMapper
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  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 getUser(Integer paramInteger)
    throws 
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { paramInteger });
      return;
    }
    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);
    }
  }

  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);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("proxy.TestProxy1$UserMapper").getMethod("getUser", new Class[] { Class.forName("java.lang.Integer") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

我简单整理一下哈:

 

 谢谢!!!

下面我贴上代码奥,有不正确的欢迎指出,大家一起进步!!

我下面的代码是动态代理的代码,跟上面的其实差不多奥!!

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface  User{
     void say();
}
class LayzUser implements User{
    public void say() {
        System.out.println("懒惰的用户在说话了");
    }
    private  void truduce() {
        System.out.println("介绍自己的方法");
    }
}
//我们的handler,具体的操作行为,用户去实现
class UserInvoke implements InvocationHandler {
    //这个才是真实的对象
    private Object o;
    public UserInvoke(Object o1){
        this.o = o1;
    }
    //proxy:代理类 method方法 args:参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----日志--------");
        Object invoke = method.invoke(o, args);//注意这里是o对象,调用对象的方法 ,方法前后进行日志打印
        System.out.println("----日志--------");
        return invoke;
    }
}
public class ProxyDemo1 {
    public static void main(String[] args) {
        //动态代理  要在对象的方法前后打印日志
        LayzUser layzUser = new LayzUser();
        //动态的生成代理类  为啥这个代理类可以调用相同的方法
        // 为了保持行为的一致性,代理类和委托类会实现相同的接口,所以在访问者看来两者没有丝毫的区别
        User o =(User) Proxy.newProxyInstance(ProxyDemo1.class.getClassLoader(), new Class<?>[]{User.class}, new UserInvoke(layzUser));
        o.say();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值