一文看懂什么是代理模式【没有废话,很硬】

写在前面

讲真,我对设计模式其实并没有很深入的了解。这里我想把自己的理解 通过文字的方式表达出来。为啥突然想起写这个文章呢?是因为我在星球里面看见有人提问:
在这里插入图片描述
其实,我在去年的时候也写过相关的内容,但是没有展开。这里我就一一把自己所知写出来。
在这里插入图片描述

那么接下来就开始吧,如果有什么错误的地方,欢迎指正~我也还在不断的学习中,大家一起加油!

核心:原有对象需要额外的功能,就可以使用代理这项技术

在这里插入图片描述
代理模式两大类:

  • 静态代理
    透明代理
  • 动态代理
    基于接口的JDK动态代理
    基于类的CgLib动态代理

01静态代理

目的:一开始就要抓住我们是去 增强 类的功能的。

所谓静态代理,大致就是需要重新写一个 代理类 去实现接口,然后这个类的构造方法 用待增强类 作为入参。在实现接口的方法中,调用 待增强类 对应的方法。同时,在这个方法的前后可以调用其余的方法,从而实现功能增强的目的。

什么?!没看懂,没关系,我们上代码

1.1 来一个接口:

public interface Subject {
    
    

     void doSomeThing();
}

1.2 实现这个接口 (就像web里面的 接口+Impl)

public class RealSubject implements Subject {
    
    
    public void doSomeThing() {
    
    
        System.out.println("我是真正的实现类,这里可能有大量的逻辑处理代码 doSomeThing()");
        
    }
}

其实到这里,就是我写代码时候的常规操作。感觉很正常嘛,写一个接口,然后再写实现类去实现这个接口定义的方法。需要使用的时候:直接

接口 接口1 = new 接口实现类();
接口1.doSomeThing();

当然这样,也是没错,OK 。

随着业务庞大,你就会知道,拥有一个 proxy 类对真实类的封装对于粒度的控制有着重要的意义?

1.3 写一个 代理类
这个类需要去实现我们的接口,同时将上面的 实现类作为入参 传递给代理类的 构造函数。

注意:我们就是在这里实现类功能的增强的!

/**
 * Description: 静态代理
 *
 * 
 * 静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,
 * 代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题。
 *
 * 缺点:如果目标对象的接口有很多方法的话,那我们还是得一一实现,这样就会比较麻烦
 *
 * @Author: 留歌36
 * @Date: 2020/5/21 11:44
 */
public class SubjectProxy implements Subject{
    
    

    // 真正的实现类
    private RealSubject realSubject;

    // 构造方法1
    public SubjectProxy(RealSubject realSubject) {
    
    
        this.realSubject = realSubject;
    }

    // // 构造方法2: 只做  RealSubject  的代理,且RealSubject对外界透明,也叫做透明代理
    public SubjectProxy() {
    
    
        this.realSubject = new RealSubject();
    }

    /**
     *  实现接口的方法
     */
    public void doSomeThing() {
    
    

        // 这个方法 之前之后 还可以做一些其他的事情,就实现了类功能的增强
        SubjectProxy.increaseBefore();

        // 通过这个静态代理就可以使用一句代码顶真正实现类 的功能实现
        realSubject.doSomeThing();


        increaseAfter();

    }


    // 1.在方法之前做增强
    private static void increaseBefore() {
    
    
        System.out.println("1.在方法之前做增强");
    }

    // 2.在方法之后做增强
    void increaseAfter() {
    
    
        System.out.println("2.在方法之后做增强");
    }


}

其实到这里,静态代理就结束了,当然我们得写一个类测试一下撒:
在这里插入图片描述

补充:所谓透明代理,就是将我们的真实的 实现类 封装进了代理里面,对于外界来说是透明的。就像:

   public SubjectProxy() {
    
    
        this.realSubject = new RealSubject();
    }

关于静态代理就是这样了,其实就是写一个代理类去实现目标对象的接口。

缺点:如果 目标对象的接口 有很多方法的话,那我们还是得一一实现,这样就会比较麻烦,所以引入动态代理来解决此类问题。

02动态代理

抓住一点:静态代理我们是手动写一个 代理类 去实现目标对象的接口,然后一一实现这些接口。这样就太难搞了,,,然后动态代理就不用一一去手动实现,我们利用 反射 技术实现这一目的。

Java提供了一个Proxy类,调用它的newInstance方法 ,该方法 返回指定接口的代理类的实例 将方法调用 分派到 指定的调用 处理程序。我

们只需要写一个动态代理的类,就直接齐活了。是不是很方便~

public class ProxyHandler implements InvocationHandler {
    
    

    private Object tar;

    // 绑定目标对象,并返回 代理对象 【这在之前我们是手写的】
    public Object bind(Object tar)
    {
    
    
        this.tar = tar;

        /**
         * 参数一:生成代理对象使用哪个类装载器【一般我们使用的是被代理类的装载器】
         *
         * 参数二:生成哪个对象的代理对象,通过接口指定【指定要被代理类的接口】
         *
         * 参数三:生成的代理对象的方法里干什么事【实现handler接口,我们想怎么实现就怎么实现】
         * 

			注意:代理对象拥有目标对象相同的方法【因为参数二指定了对象的接口,代理对象会实现接口的所有方法】
         */
       
        return Proxy.newProxyInstance(

                tar.getClass().getClassLoader(),

                tar.getClass().getInterfaces(),

                this // 这里的this,即上面定义的Object,代表实现的所有方法 交由Object 的 invoke() 反射方法进行处理
        );
    }

    // 用户调用代理对象的什么方法,都是在调用处理器的invoke方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    

        Object result = null;

        //这里就可以进行所谓的AOP编程了,不管你调用 生成对象的什么方法,invoke都是会触发,这里就可以做一些前置或后置的方法
        // increaseBefore() 方法

        //在调用具体函数方法前,执行功能处理【这里就是调用生成对象的 具体方法】
        result = method.invoke(tar,args);

        // increaseAfter() 方法

        //在调用具体函数方法后,执行功能处理
        return result;

    }
}

通过动态代理实现的全部方法,全都是通过invoke()方法调用
在这里插入图片描述

这里,我在代码中也写了大量的说明,只要知道,我们传入一个 目标对象的实例 ,就能得到一个 动态生成的代理类,这个类拥有 传入的目标对象实例的全部 默认实现方法。

在调用这个目标对象实例的方法的时候,会触发invoke()中定义的增强功能。

代理对象的生成,是利用 JDK API,动态地在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型),并且会默认实现接口的全部方法。

补充: 基于接口的JDK动态代理 && 基于类的CgLib动态代理
在这里插入图片描述
上面是我小伙伴总结的,我觉得写得不错,就贴过来了,欢迎关注他的博客地址

说了那么多,可是真正回归到我们日常写代码中:

  1. 我知道Spring的AOP(面向切面编程)底层 其实就是动态代理来实现的,其实也没有很熟悉

  2. 讲真,我就不大知道了,后面我有知道,再回来补充

然后差不多,代理模式就写到这里吧。

核心:原有对象需要 增强 功能,就可以使用代理这项技术

下一篇写装饰器模式

猜你喜欢

转载自blog.csdn.net/liuge36/article/details/106339866
今日推荐