动态代理

发布时间 2024-01-13 00:46:08作者: chen平安在安平cheng

咱们来聊聊动态代理,大家最开始听到这个词的时候肯定很懵,我也是这样的。同时大家脑海中肯定也会想到是不是会有静态代理呢?答案是肯定的。想要对动态代理了解透彻,首先需要先了解什么是代理。

1.代理

听到代理这个词,相信大家在心中知道了这个的词的作用与含义。在日常生活中大家肯定见过或者说知道这么些个场景。例如:大家去租房或者说买房,是不是有房屋中介会联系到我们。我们向中介诉说我们的需求,而我们只需要等待,在等待期间中介会根据我们的需求去找到匹配房源,然后向我们推荐。
在上面的场景中,房屋中介代替我们去做了寻找房源的事情,我们可以称房屋中介为代理。
类似的场景还有:商品代购、经纪人等等。

在讲解静态代理和动态之前,咱们先来了解下代理模式。

2.代理模式

代理模式是一种设计模式,它为其他对象提供一个代理以控制对这个对象的访问。在代理模式中,代理对象(Proxy)代表了目标对象(Real Subject),并提供了与目标对象相同的接口。客户端可以通过代理对象间接调用目标对象的方法,而代理对象可以在调用前后增加额外的操作,比如权限检查、日志记录、缓存处理、延迟加载等。

相信有读者看完这段话还是不能理解,没关系。下面咱们用代码实现代理看看,读者后面再来看看这段话相信就有自己的理解了。

3. 静态代理
在先讲解动态代理之前,咱们先讲解什么是静态代理。

定义接口

点击查看代码
package com.demo.proxy;

/**
 * 接口
 */
public interface Star {
    String sing(String name);
    String dance(String dance);
}

定义被代理类

点击查看代码
package com.demo.proxy;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 被代理类
 */
@Data
@AllArgsConstructor
public class BigStar implements Star{
    private String name;



    @Override
    public String sing(String song) {
        System.out.println(this.name+"正在唱歌:"+song);
        return "谢谢你们喜欢我的歌";
    }

    @Override
    public String dance(String dances){
        System.out.println(this.name+"正在跳舞:"+dances);
        return "谢谢你们喜欢我的舞";
    }
}

定义代理类

点击查看代码
package com.demo.proxy;
/**
 * 代理类
 */
public class StaticProxy implements Star{

    private BigStar bigStar;

    public StaticProxy() {
    }

    public StaticProxy(BigStar bigStar) {
        this.bigStar = bigStar;
    }

    @Override
    public String sing(String name) {
        /*代理对象增强的部分*/
        System.out.println(System.currentTimeMillis());
        /*被代理对象调用方法*/
        String s = bigStar.sing(name);
        /*代理对象增强的部分*/
        System.out.println(System.currentTimeMillis());
        return s;
    }

    @Override
    public String dance(String dance) {
        return null;
    }
}

测试

我们来回顾下静态代理的实现:
(1)代理类是自己手工实现的,自己创建一个Java类,表示代理类。
(2)同时你所要代理的目标是确定的。

总结来说静态代理:目标类和代理类实现了相同的接口,在代理类中依赖了目标类,代理类的方法中调用了目标类的方法,并做了一些增强性的工作。

同时也可以发现静态代理的缺点:
(1)当目标类增加了,代理类可能也需要成倍的增加,代理类数量过多。
(2)当你的接口中功能增加了,或者修改了,会影响众多的实现类,厂家类,代理都需要修改,影响比较多。

4.动态代理

动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类。

动态代理的实现方式常用有两种:

  • 使用JDK代理。
  • 通过CDLIB代理。

在本文着重讲解JDK动态代理,jdk动态代理中最重要的两个分别是Proxy类和InvocationHandler接口。(要求目标对象必须实现接口

Proxy类的newProxyInstance方法

点击查看代码
/*参数1:用于指定类加载器 去加载生成的代理类  写法固定:一般用当前类的类加载器
  参数2:用于指定生成的代理长成什么样子,也就是有哪些方法
  参数3:用于指定生成的代理对象 做什么事情InvocationHandler 是个接口*/
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

InvocationHandler接口的invoke方法

点击查看代码
// Object proxy:jdk创建的代理对象,无需赋值
// Method method:目标类中的方法
// Object[] args:目标类中方法的参数
public Object invoke(Object proxy, Method method, Object[] args)

动态代理步骤

创建接口,定义目标类要完成的功能

点击查看代码
package com.demo.proxy;

/**
 * 接口
 */
public interface Star {
    String sing(String name);
    String dance(String dance);
}

创建目标类,实现该接口

点击查看代码
package com.demo.proxy;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 被代理类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BigStar implements Star{
    private String name;



    @Override
    public String sing(String song) {
        System.out.println(this.name+"正在唱歌:"+song);
        return "谢谢你们喜欢我的歌";
    }

    @Override
    public String dance(String dances){
        System.out.println(this.name+"正在跳舞:"+dances);
        return "谢谢你们喜欢我的舞";
    }
}

创建 InvocationHandler 接口的实现类,在invoke()方法中完成代理类的功能

点击查看代码
package com.demo.proxy;

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 {
        /*代理对象做的事 会在这里写代码*/
        if(method.getName().equals("sing")){
            System.out.println("收钱,20w");
            //return method.invoke(star,args);
        }else if(method.getName().equals("dance")){
            System.out.println("收钱,10w");
            //return method.invoke(star,args);
        }
        return method.invoke(target,args);
    }
}

测试

动态代理执行流程

望各位大佬指正补充。