前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代理模式 教你:先领券 再消费!

代理模式 教你:先领券 再消费!

作者头像
浩说编程
发布2022-11-11 09:46:11
2040
发布2022-11-11 09:46:11
举报
文章被收录于专栏:Java经验之谈

视频版 - 看着更方便:

哔哩哔哩(横板)👉 https://b23.tv/CvCn35C

小红书(竖版)👉 http://xhslink.com/GWMlCi

其实 代理模式 的思路非常好理解

"代理"这个词

我们在网购的时候应该经常会听到

比如:

“我们是 某某品牌的 代理商”

“你在我这里消费可以 领取优惠券 更便宜"

01 | 代理模式

所以代理模式就是说

我在 消费 某个方法的时候

不直接调用 方法所在类

而是通过中间的 代理类

在不改变原方法的基础上

对 原方法 增加额外的附加功能

这种"代理"的思想在实际开发中的典型应用就是 代码解耦

什么意思呢?

我们知道在开发中 除了 业务处理代码 还有一些 公共处理代码

像 记录日志......

这类代码其实完全没有必要和业务处理代码耦合在一起

所以可以应用 代理模式

将之解耦,放到代理类中

这样既不影响原方法

又能灵活的修改代理类

那接下来 我就以 记录日志 为例

演示一下 java应用 代理模式 的过程

02 | 静态代理

首先 定义一个消费接口以及它的实现类

其中包含一个“购物”方法

代码语言:javascript
复制
//接口
public interface ProducerService{
    Product makeProduct();
}
//服务接口实现类
public class ProducerServicelmpl implements ProducerService{
    @Override
    public Product makeProduct(){
        Product product =new Product();
        return product;
    }
}

然后 创建代理类 同样实现消费接口

代码语言:javascript
复制
//代理类
public class ProducerServiceProxy implements ProducerService{
    //实例化被代理类
    private ProducerService productService=new ProducerServicelmpl();
    @Override
    public Product makeProduct(){
        //原方法
        Product product=productService.makeProduct();
        //日志记录逻辑代码
        .....
        return product;
    }
}

在代理类中先实例化原来的实现类,也就是被代理类

接着重写 “购物”方法

在方法中 调用原"购物"方法的同时

增加额外的 日志记录 或其它功能

这样就实现了代理模式的一种

叫做 静态代理

静态代理的意思是

我们需要在代码编译运行之前预先创建好代理类

也就是说 如果我有十个类需要 记录日志

那就要预先写好十个代理类

这显然不是好的实现方式

于是引出了另一种代理模式的实现 动态代理

03 | 动态代理

动态代理的思路是

不需要预先写好代理类

而是编写一个公共的 代理配置类

然后在需要创建代理的时候

将 被代理类作为参数 传给 代理配置类

由代理配置类生成对应的 代理类

来看具体代码

代码语言:javascript
复制
//定义公共代理配置类
public class ProxyHandle implements InvocationHandle{
    private Object prtoBeProxyService;
    //构造函数
    public ProxyHandle(Object toBeProxyService){
        this.toBeProxyService=toBeProxyService;
    }
    @Override
    public Object invoke(Object proxy,Method method,Object args) throws Throwable {
        //执行原方法
        Object invoke =method.invoke(subject,args)
        //日志记录逻辑代码
        .....
        return invoke;
    }
}

首先 创建一个 代理配置类

注意 它和普通类的区别是

必须实现 InvocationHandler 接口

它是java实现动态代理的关键

我们继续看里面的代码

先用构造函数来初始化被代理的对象

这里涉及一个知识点

Object 是 所有类的默认父类

也就是说下面这个等式是成立的:

代码语言:javascript
复制
class A{} = class A extends Object{};

所以 Object 可以接收任何类对象

接着重写 InvocationHandler 的 invoke方法

当我们调用原方法的时候

会被转发到这个方法中

所以这里就是我们对原方法进行功能扩展的地方了

其中入参

proxy 表示生成的代理类

method 表示原方法对象

args 表示原方法需要的参数

这就是 代理配置类 的代码了

接着我们看一下 调用动态代理 的示例代码:

代码语言:javascript
复制
//实例化服务
ProducerService producerService=new ProducerServicelmpl();
//创建代理配置类
ProxyHandle proxyHandle=newProxyHandle(producerService);
//生成代理类
ProducerService proxylnstance=(ProducerService)Proxy.newProxyinstance(
    producerService.getClass().getClassLoader()
    ,producerService.getClass().getinterfaces()
    ,proxyHandle);
//调用方法
proxylnstance.makeProduct()

1、先创建被代理类实例

2、将被代理类作为入参,创建 代理配置类 实例

3、调用 Proxy 类的 newProxyInstance 方法创建代理类

这个Proxy类 是用来创建 代理类 的一个工具类

4、拿着上一步生成的动态代理类,调用目标方法

这个时候就会进入 代理配置类 的invoke方法执行代理逻辑

总结一下动态代理的实现

重写 InvocationHandler 的 invoke方法

然后调用 Proxy 工具类 创建代理对象

以上是基于 接口 来实现的动态代理(由jdk提供)

你可以看到必须要实现接口

04 | cglib

而另一种不基于接口的实现方式叫做: cglib

cglib 是一款开源的代码生成类库

可以动态的为普通类生成代理

所以在spring 中

如果目标类实现了接口,则使用jdk的方式来实现动态代理

如果没有实现接口,则使用cglib的方式来实现

我是浩说

帮你入门到放弃

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浩说编程 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档