代理模式记录

代理模式解决的问题:对于系统的一个类中的很多方法或一系列的类,需要在其执行之前或之后进行增强处理(例如添加日志),这时候就可以使用代理简化代码,不用每个地方都添加重复代码。

代理实现的方式

代理实现的划分:目前根据其能达到的代理的功能特性来划分,基础的方式只能代理固定的类,被叫做静态代理;JDK与CGLIB支持动态的类,被叫做动态代理,实际使用过程中还是动态代理好使,毕竟是已经封装好的工具。

  1. 静态代理
    静态代理只固定代理一个类,也就是在原有类的方法执行之前或之后添加需要执行的逻辑。
    核心:代理类持有被代理类的对象,和被代理类保持同样的方法结构(可实现通过杨的接口或自己控制)
    例如:我现在有一个查询数据库的公共Service
    在这里插入图片描述
    其实现是直接查询数据库数据
    在这里插入图片描述
    但是现在要求将所有的数据库查询先走Redis缓存查询,所以我就添加了数据库查询的代理类,和数据库查询的类实现同一个接口,其中持有了数据库查询的对象,在实现查询时先执行redis查询再使用DB查询的对象执行原有方法
    在这里插入图片描述
    总结:静态代理和装饰者有点像,但是装饰者是拿固定的方法作为功能块直接继承来用(没创建对象),代理则更侧重于整个类的代理,持有原来的对象干活儿。
    另外,静态代理的写法其实是有点像策略模式的,只是第二种策略代理了第一种策略,场景不一样

  2. 动态代理
    如果让你手写动态代理,你会怎么写?
    动态代理,顾名思义,其意思是动态的代理一些类,不需要你每个像静态代理那样手写其代理类。
    我觉得按照逻辑讲有以下几步:
    第一步:定位需要代理的目标群体
    可能的场景:需要代理的可能是多个类,这些类可能在某个固定文件夹下,也可能分布在不同地方
    如何找到这些类?一般人肯定会对这些类做标识,在代码里面其实注解就是标识的一种。另一种则是主动告知,例如mybatis指定mapper文件的位置注解,其蕴含了目标文件的位置(没错,mybatis也用了代理模式)
    在这里插入图片描述
    第二步:获取需要代理类的对象
    有了位置信息即可进行下一步,获取需要代理类的对象,并进行代理操作。目前只知道类的位置,如何获取其对象?直接反射一套带走啊

String className = "com.example.MyClass";
Class<?> clazz = Class.forName(className);
MyClass obj = (MyClass) clazz.getDeclaredConstructor().newInstance();

第三步:完成代理
理论上来讲,在第二步获取到了被代理类的对象后直接通过对象调用其方法,在调用方法前或方法后添加增强逻辑即可。

JDK代理使用方法:

创建代理处理类 JdkInvocationHandler,JDK InvocationHandler暴露出代理类的执行方法,方便添加逻辑
在这里插入图片描述
代理类使用方式
在这里插入图片描述

将JDK生成的代理类显示到项目同级
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

查看JDK生成的代理类发现其也是实现了被代理类所实现的interface,和静态代理的写法一样
在这里插入图片描述
但是在其实现查询数据库方法部分有所不同
在这里插入图片描述
super.h,从$Proxy0.class的父类查看h代表了代理处理类,即JdkInvocationHandler
在这里插入图片描述
m3代表了查询数据库Service的getData方法
在这里插入图片描述
所以代理类中getData最终的实现是调用JdkInvocationHandler中的invoke方法,第一个参数是当前生成的代理类 Proxy0,第二个参数是DataService的getData方法,讲到底这玩意最终只是为了调用被代理的方法,费劲,然后invoke就回到了最开始handler暴露的入口。。。
在这里插入图片描述
在handler里面的invoke写东西就相当于在代理类的getData实现里面写东西,妙啊。
漏了一步,代理类的创建通过Proxy类提供的API传入目标类以及我们的handler即可

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
DataService dataService  = jdkInvocationHandler.getProxy();
dataService.getData();

在这里获取到的代理类其实就是DataService 的一个实现类对象,所以用的DataService 接的,调用getData方法实际就会走代理类Proxy0的实现!
其大概过程如下:
在这里插入图片描述

另:cglib的代理下篇再整理,代理这玩意写的复杂,实际也就那点功能

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值