JDK动态代理入门

介绍

要了解动态代理,首先要知道什么是代理,在笔者看来,代理的功能概括来说就是:在不修改被代理类代码的情况下给这个类包含的方法增加某些功能
**至于为什么要不修改这个被代理类?**可能是为了满足开闭原则,可能是想把这个被代理类给隐藏起来,等等 。原因可能有很多,但概括起来就是不修改代理类。

要增加什么功能呢?(后文提到的增强指的就是增加功能)
这个就看使用者怎么写了,这个是非常灵活的,常用的就是增加日志统计方法耗时

我熟知的动态代理通常有两种,即JDK动态代理CGLIB动态代理

笔者最近学习了JDK动态代理,所以编写这个博客输出一下,因为笔者也是初学,了解的不多,尽可能写的详细~
好处是,笔者知道初学者的学习的难点在哪,应该更能帮助初学者理解~
坏处嘛,嘿嘿,如果教错了,那就抱歉啦~

JDK动态代理

笔者前面前面提到过JDK动态代理是基于接口来实现的,具体怎么个实现法,参考下面这张图。
代理类实现了与被代理类相同的接口,那么相应的代理类要实现对应的接口方法
既然是要增强被代理类某些方法的功能,那么思考一下,代理类实现接口方法时方法中应当包含那些内容?
答案显而易见:实现新增功能的代码 + 调用被代理类对应的方法

在这里插入图片描述

比如我想统计一个方法的执行时间,那么伪代码如下

void test (Object[] args){
   
   
	1. 统计开始时间
	2. 调用被代理类的test方法
	3. 统计结束时间
	4. 计算整体耗时
}

鲁迅曾经说过:光说理论不给代码,那就是在耍流氓(鲁迅:也许我没说过?

客官稍安勿躁,细想一下要实现如上的功能我们需要解决的两个问题:

  • 代理对象怎么创建?
  • 增强功能肯定是要写代码的,这个代码写在哪?

代理对象怎么创建

非常非常简单,java.lang.reflect中有一个类Proxy, 这个类中有个静态方法Proxy.newProxyInstance(),通过这个方法我们可以获取某个对象的代理对象。

啪一下就蹦出来个陌生的方法就, 问你怕不怕? 别怕,慢慢来~

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

这个静态方法有三个参数需要提供(这个静态方法还有一个重载方法,我们不需要关注)

  • ClassLoader loader : 被代理对象的类加载器
  • Class<?>[] interfaces: 被代理对象实现的接口
  • InvocationHandler h :一个InvocationHandler接口的实现类

问:为什么需要被代理对象的类加载器?
答:所谓动态代理,动态的点就在于JVM会帮我们生成代理类的字节码文件并加载,然后实例化,这过程就需要类加载器ClassLoader,为了和被代理对象保持一致,所以就使用被代理对象的类加载器进行加载。

问:为什么需要被代理对象的接口集合?
答:这个接口本质上就是告诉代理对象,哪些方法是我想要增强的。 也就是说,提供的所有接口中的所有方法,就是JVM帮我们创建的代理对象所能代理的方法,也就是我们可以对其进行功能增强的方法。

这也意味着,并非需要把被代理类实现的所有接口传递进去,仅仅需要将包含我们想要增强方法的接口传递进去即可。
如被代理类 Test实现了两个接口,分别是接口A,接口B, 现在我想增强接口A中的方法,这个时候,传递进去的接口集合中仅仅需要接口A。

问:这个InvocationHandler接口是个什么东东?
答:这个就涉及到我们前面提到的第二个问题:新增功能的代码我们要写在哪里?, 答案就是这个InvocationHandler里 ,InvocationHandler接口中只有一个方法需要我们实现,那就是invoke方法,准确的说,我们要新增的代码功能,就是写在这个invoke方法里的。
Object invoke(Object proxy, Method method, Object[] args)
客官先别急,这个方法具体怎么用我们后面会提到,现在我们只需要有一个认知:我们想要增强的功能是写在invoke这个方法里的,因此我们需要创建一个类实现InvocationHandler接口并实现其中的invoke方法,并将这个类当做参数传给newProxyInstance方法

理清了这三个参数,成功调用Proxy.newProxyInstance方法,我们就可以获取到代理类对象。

举例

举个具体的例子:

接口:

public interface JDKTest {
   
   
    void hello();
    String eat(String food);
}

被代理类:

public class JDKTestImpl implements JDKTest{
   
   


    @Override
    public void hello() {
   
   
        System.out.println("hello");
    }

    @Override
    public String eat(String food) {
   
   
        return "吃了" + food;
    }
}

InvocationHanlder实现类:

package com.zp.myproject.demo;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
   
   
    private Object target;

    public MyInvocationHandler(Object target){
   
   
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
   
        System.out.println(method.getName()+"实现了代理增强");
        return method.invoke(target,args
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值