当前位置:首页 > CN2资讯 > 正文内容

设计模式 - 静态代理 VS 动态代理静态代理与动态代理

2天前CN2资讯
QA

动态代理是什么?有哪些应用?

动态代理是运行时动态生成代理类。

动态代理的应用有 spring aop、hibernate 数据查询、测试框架的后端 mock、rpc,Java注解对象获取等。

 

怎么实现动态代理?

JDK 原生动态代理和 cglib 动态代理。

  • JDK 原生动态代理是基于接口实现的 

!!!重要的两个类!!!
Proxy类
Proxy.newProxyInstance 用来生成代理实例
InvocationHandler接口
要@Override invoke()方法,拦截所有原始类的各种方法,可在其前后增加逻辑

  •  
  • 而 cglib 是基于继承当前类的子类实现的

!!!重要的两个类!!!
Enhancer类
Enhancer.create(clazz, this) 获取被代理后的目标类
MethodInterceptor接口
要@Override intercept()方法,拦截所有原始对象的各种方法,可在其前后增加逻辑

  •  
1-为什么需要代理?

当想给一个类的每个method进行扩充(统计、打印耗时)、拦截(判断是否登录)时:

常规思路

  • 修改了原来的代码逻辑
  • 每个涉及的method都需要改动,改动量很大

代理思路

可以使用代理(静态代理/动态代理),统一处理这类额外功能(非核心业务功能),让原来的代码仍然只关心最核心的业务逻辑。

 

2-静态代理

关键点

代理类ServiceImplProxy和被代理类ServiceImpl实现同样的Service接口

代理类ServiceImplProxy持有被代理类ServiceImpl的引用

代理类ServiceImplProxy在接口方法中,填充扩展/拦截功能,核心逻辑依然由被代理类ServiceImpl的引用来完成

  

代码实例

接口 service



public interface Service {

void play(String xxx);

String run(String xxx);

}


 

被代理类 ServiceImpl



public class ServiceImpl implements Service{

@Override
public void play(String xxx){
//....
}

@Override
public String run(String xxx){
//...
}

}


 

代理类 ServiceImplProxy



public class ServiceImplProxy implements Service{

private Service service;

//***关键*** 持有ServiceImpl的引用
public ServiceImplProxy() {
service = new ServiceImpl();
}

/**
* 扩展功能
*/
@Override
public void play(String xxx){
long start = System.currentTimeMillis();//计时开始

//***关键*** 执行真正的逻辑
service.play(xxx);

long end = System.currentTimeMillis();//计时结束
System.out.println("耗时:" + (end - start) + "毫秒");//打印耗时

}

/**
* 拦截功能
*/
@Override
public String run(String xxx){
//添加拦截逻辑
if("xxx".equals("...")){
//***关键*** 执行真正的逻辑
service.run(xxx);
}
//...
}

}


 

 

优缺点

优点:

  • 可以不修改原目标类(指ServiceImpl)的代码
  • 可以在代理类中对功能进行拦截和扩充

缺点:

  • 代理类需要实现与目标类一样的接口,会导致代理类数量较多,不易维护
  • 一旦接口增加方法,目标类和代理类都需要维护

鉴于这两个缺点,JDK 提供了动态代理

 

 

3-动态代理,JDK(基于接口)

 

 

为何要引入JDK动态代理

为了解决静态代理的带来的以下问题 -> 引入了JDK动态代理:

  • 代理类需要实现与目标类一样的接口,会导致代理类数量较多,不易维护
  • 一旦接口增加方法,目标类和代理类都需要维护

 

代码示例

JDK动态代理的实现和静态代理一样,不同的是代理类的创建方式不同:

  • 静态代理是直接新增一个代理类。
  • JDK动态代理需要
  • 持有目标类对象 - 代理类的通过构造方法传入目标类对象(会),代理类持有目标类对象 (第1步掌握“目标类的实例”,与第2步自动生成代理类无关(因为Proxy.newProxyInstance只需传入clazz,不需要实例),与第3步反射调用方法有关(因为哪怕增加别的逻辑,但核心逻辑依然要调用“目标类的实例”)
  • 创建代理对象 - 通过JDK的Proxy类, Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法获取代理对象, 和一个"调用处理器InvocationHandler"来实现的,通过Proxy来生成代理类实例,而这个代理实例通过调用处理器InvocationHandler的invoke()接收不同的参数, 反射调用真实对象的方法。
  • 代理类实现 InvocationHandler 接口,重写invoke(Object proxy, Method method, Object[] args)方法。在此需要反射调用第1步传入的“目标类的实例”method.invoke(“目标类的实例”, args),并在此周围添加更多的逻辑,如过滤器等。

    1-实现JDK动态代理的util代码(拷贝到任何项目中,都能直接使用) 



    !!!重要的两个类!!!
    Proxy类
    Proxy.newProxyInstance 用来生成代理实例
    InvocationHandler接口
    要@Override invoke()方法,拦截所有原始类的各种方法,可在其前后增加逻辑


     

     

    2-实际例子

     

     

       

     

    优缺点

    优点:见“为何要引入JDK动态代理”

    缺点:只能对该类,所实现接口中定义的方法,进行代理。 

     

    详细解析

    • JDK 动态代理
    • JDK动态代理原理+为何只能代理接口,不能代理类

     

     

    4-动态代理,CGlib(基于类)

    为何要引入CGlib动态代理

    为了解决 JDK 的动态代理无法代理不实现接口的类的问题 -> 引入使用 CGLib 的实现动态代理。

    CGLib(Code Generator Library)是一个强大的、高性能的代码生成库。底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。动态生成一个目标类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

     

    关键点

    • CGlib动态代理需要
    • maven中添加cglib依赖
    • 不再持有目标类对象 - 构造函数就是默认的空构造函数
    • 创建代理对象 - 使用cglib自带的Enhancer.create(clazz), 参数是目标类的clazz对象。Enhancer类是CGLib中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展,以后会经常看到它。
    • 定义拦截器/处理器 - 在调用目标方法时,CGLib会回调MethodInterceptor(Object obj, Method method, Object[] params, MethodProxy proxy)接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口
    • 参数:Object为由CGLib动态生成的代理类实例,Method为上文中实体类所调用的被代理的方法引用,Object[]为参数值列表,MethodProxy为生成的代理类对方法的代理引用。
    • 返回:从代理实例的方法调用返回的值。
    • 其中,proxy.invokeSuper(obj,arg) 调用代理类实例上的proxy方法的父类方法(即实体类TargetObject中对应的方法)

     

    优缺点

    优点:完全不受代理类必须实现接口的限制

    缺点:对于final方法,无法进行代理

     

     ​

     

      你可能想看:

      扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/24152.html

      分享给朋友:

      “设计模式 - 静态代理 VS 动态代理静态代理与动态代理” 的相关文章

      香港虚拟机:提升业务效率与稳定性的最佳选择

      香港虚拟机:提升业务效率与稳定性的最佳选择

      香港虚拟机的定义与应用场景 香港虚拟机是一种基于云计算技术的虚拟服务器服务,它允许用户在香港的数据中心中运行应用程序和存储数据。这种服务特别适合需要低延迟、高带宽和稳定网络连接的场景,比如在线游戏、电子商务平台、金融服务和跨国企业的远程办公系统。香港作为国际金融中心,其数据中心的基础设施和网络连接质...

      全球主机交流论坛:提升技术的最佳平台

      全球主机论坛概述 在当今数字化时代,全球主机论坛扮演着越来越重要的角色。这些论坛不仅是技术爱好者的聚集地,更是为需要域名、主机、VPS和服务器信息的用户提供了一个交流的平台。我作为一名站长,经常在这样的论坛上交流经验、获取灵感和解决技术难题,论坛的存在极大地丰富了我的网络建设之旅。 主机论坛的定义其...

      2023年最佳VPS服务商排名与推荐

      在数字化时代,VPS(虚拟专用服务器)成为了很多企业和开发者青睐的主机解决方案。简单来说,VPS是将一台物理服务器划分成多个虚拟服务器,每个虚拟服务器都能够独立运行它自己的操作系统和应用。这样的设计不仅提升了资源利用率,还为用户提供了更高的灵活性与控制权,尤其适合需要稳定性能的中小型企业和开发者。...

      狗云实名认证的重要性与服务体验

      狗云简介 提起狗云(Dogyun),首先让我想起的是它在国内主机服务商中崭露头角的那段经历。成立于2019年,这家由国人创办的云服务平台,积极响应了市场对高质量、低价格VPS服务的需求。服务范围覆盖美国、日本和中国香港等地,让不少技术爱好者和企业客户看到了更多选择的可能。由于其价格相对亲民,狗云逐渐...

      探索锡考克斯:舒适的居住地与丰富的旅游体验

      锡考克斯(Secaucus)是一个坐落于新泽西州的小镇,距离繁华的纽约市仅有不到10公里的路程。这使得锡考克斯成为一个非常吸引人的居住地和旅游目的地。首先,锡考克斯的地理坐标是纬度40.782和经度-74.0676,位于北纬40°46′55″和西经74°4′3″之间。这种优越的地理位置无疑为它的经济...

      阿里云新用户优惠活动详解:如何高效利用云服务

      作为阿里云的新用户,我感到兴奋,因为阿里云为像我这样的新手提供了许多优惠和服务,让我能轻松地体验云产品。首先,我们来聊聊什么是阿里云新用户。简单来说,阿里云会通过是否购买过云产品来判断我是否是新用户,而并非仅仅看注册时间。这意味着,只要我没有购买过云服务,就能享受到新用户的特权。 新用户的权益和优惠...