Java的JDK动态代理实现

Java的JDK动态代理实现

  1. 动态代理在自己的记忆里模模糊糊,所以我决定把这个实现的过程写下来,记录一下。

动态代理有什么用?

  1. 我的理解很粗暴:就是对原用功能的增强或者修改。
  2. 想想我们平时使用的梯子,那也是一种代理,对我们的请求进行一顿操作,让我们能够访问外网,代理就是干的这样一个火。
  3. java的动态代理也一样,原来的类功能已经固定下来了,我在不修改源码的情况下在使用类的方法时进行日志记录?动态代理就是一个方法,在调用源码的方法的时候,在调用这个方法的前后可以增加一点自己想要的操作。

实现开始咯,JDK动态代理是基于接口的,所以我们先把接口,和类创建出来

  1. 这是文件的结构
    在这里插入图片描述

  2. 接口

public interface manDo {
    public void manDo();
    public void NotManDo();
}
  1. 接口的实现类
public class Man implements manDo{
    @Override
    public void manDo() {
        System.out.println("重写 mando");
    }

    @Override
    public void NotManDo() {
        System.out.println("重写 notMando");
    }
}

上面这里就像我们拿到的源码,我们如何在不修改Man这个源码的情况下进行方法的增强?

  1. 首先我们要创建代理类,这个代理类需要换入的参数是实现了接口的类,即实现了manDo接口的Man这个类。这个代理一定要实现InvocationHandler 接口,并且通常定义一个Object对象,通过构造方法传入实现了接口的类。然后我们在里面重写invoke方法进行代理。可以看到我这里还通过method.getName判断了要执行的方法名,如果是manDo则执行对应的增强
public class ManProxy implements InvocationHandler {
    public Object obj;

    public ManProxy(Object target) {
        this.obj = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        if (method.getName() != "NotManDo") {
            System.out.println("before : 这是man do的事情");
            object = method.invoke(obj, args);
            System.out.println("after : 这是man do的事情");
        } else if (method.getName() != "manDo") {
            System.out.println("before : 这^-^不是man do的事情");
            object = method.invoke(obj, args);
            System.out.println("after : 这^-^不是man do的事情");
        }
        return object;
    }
}
  1. 接下来是创建我们jdk动态代理的类实例,然后进行调用了
public class ClassHandler {
    public static void main(String[] args) throws ClassNotFoundException {
        Man man = new Man();
        Class aClass = Class.forName("originClass.Man");
        ClassLoader classLoader = aClass.getClassLoader();
        Class[] interfaces = aClass.getInterfaces();
//        ClassLoader classLoader = man.getClass().getClassLoader();
//        Class[] interfaces = man.getClass().getInterfaces();
        InvocationHandler manProxy = new ManProxy(man);
        manDo man_proxy = (manDo)Proxy.newProxyInstance(classLoader, interfaces, manProxy);
        man_proxy.manDo();
        System.out.println("--------");
        man_proxy.NotManDo();
    }
}
  • 创建动态代理使用的是Proxy.newProxyInstance方法,传入一个类加载器,方法接口,然后就是代理类。
  • 值得注意的是我这里的类加载器使用的是通过Man类的得到的,实际上这个类加载器使用程序的任一个类的得到的都可以。例如通过 ClassHandler.class.getClassLoader()一样可以获得,一样可以执行。
  • 另外,可以看到我中间有注释两行为 ClassLoader classLoader = man.getClass().getClassLoader();Class[] interfaces = man.getClass().getInterfaces();这是我一开始获取方法和加载器的方法,后面我使用通过自己主动写类名originClass.Man来获得这些。
  • 还有一点我卡bug了的是,manDo man_proxy = (manDo)Proxy.newProxyInstance(classLoader, interfaces, manProxy);这里的强转类型是转为接口manDo,不能转为这个接口的实现类Man。一开始我就是选择转为Man,然后咔咔报错。理由的话我认为是这种代理方式是基于接口的,因此实现的代理类其实就是对接口的方法进行增强,因此我们转型的时候转成接口类型,也没毛病!
  • 发现神奇的地方了吗,只要我知道这个类的全类名,我就可以通过反射去实现这个类动态代理类。

当然这是JDK动态代理的方法,意思是说这一切都要基于我们想代理的类它是实现了接口的。如果没有实现接口的类的动态代理,是另一种代理方式了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值