广告
返回顶部
首页 > 资讯 > 后端开发 > Python >jdk动态代理和cglib动态代理详解
  • 655
分享到

jdk动态代理和cglib动态代理详解

2024-04-02 19:04:59 655人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录静态代理基于继承的方式实现静态代理基于聚合的方式实现静态代理继承与聚合方式实现的静态代理对比动态代理jdk动态代理如何实现一个HashMap的动态代理类?Cglib动态代理JDK

如上图,代理模式可分为动态代理和静态代理,我们比较常用的有动态代理中的jdk动态代理和Cglib代理,像spring框架、hibernate框架中都采用了JDK动态代理,下面将结合代码阐述两种代理模式的使用与区别。

静态代理

静态代理的代理对象和被代理对象在代理之前就已经确定,它们都实现相同的接口或继承相同的抽象类。静态代理模式一般由业务实现类和业务代理类组成,业务实现类里面实现主要的业务逻辑,业务代理类负责在业务方法调用的前后作一些你需要的处理,如日志记录、权限拦截等功能…实现业务逻辑与业务方法外的功能解耦,减少了对业务方法的入侵。静态代理又可细分为:基于继承的方式和基于聚合的方式实现。

场景:假设一个预减库存的操作,需要在预减的前后加日志记录(我这里是SpringBoot项目

基于继承的方式实现静态代理



public interface OrderService {
    //减库存操作
    void reduceStock();
}


@Slf4j
public class OrderServiceImpl implements OrderService {
    @Override
    public void reduceStock() {
        try {
            log.info("预减库存中……");
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


@Slf4j
public class OrderServiceLogProxy extends OrderServiceImpl{
    @Override
    public void reduceStock() {
        log.info("预减库存开始……");
        super.reduceStock();
        log.info("预减库存结束……");
    }
}

    
    @Test
    public void testOrderServiceProxy(){
        OrderServiceLogProxy proxy = new OrderServiceLogProxy();
        proxy.reduceStock();
    }

输出结果

14:53:53.769 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceLogProxy - 预减库存开始……
14:53:53.771 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceImpl - 预减库存中……
14:53:54.771 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceLogProxy - 预减库存结束……

可以看到,OrderServiceLogProxy已经实现了为OrderServiceImpl的代理,通过代理类的同名方法来增强了业务方法前后逻辑。

基于聚合的方式实现静态代理

聚合的意思就是把业务类引入到了代理类中,接口和业务实现类还是之前的OrderService、OrderServiceImpl,代理类改为如下:



@Slf4j
public class OrderServiceLogProxy2 implements OrderService {
    private OrderServiceImpl orderService;
    public OrderServiceLogProxy2(OrderServiceImpl orderService) {
        this.orderService = orderService;
    }
    @Override
    public void reduceStock() {
        log.info("预减库存开始……");
        orderService.reduceStock();
        log.info("预减库存结束……");
    }
}

    
    @Test
    public void testOrderServiceProxy2() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        OrderServiceLogProxy2 proxy2 = new OrderServiceLogProxy2(orderService);
        proxy2.reduceStock();
    }

测试输出结果和上面的结果是一致的。

继承与聚合方式实现的静态代理对比

结合上面的代码来看,如果此时需要叠加代理功能,我不仅要记录预减日志,还要增加权限拦截功能,这个时候如果采用继承的方式的话,就得新建一个代理类,里面包含日志和权限逻辑;那要是再增加一个代理功能,又要新增代理类;如果要改变下代理功能的执行顺序,还是得增加代理类,结合上面分析来看,这样做肯定是不妥的。但是如果使用聚合方式的方式呢?我们稍微改造下上面使用的聚合方式实现的静态代理代码:

首先是日志代理类代码



@Slf4j
public class OrderServiceLogProxy3 implements OrderService {
    //注意,这里换成了接口
    private OrderService orderService;
    public OrderServiceLogProxy3(OrderService orderService) {
        this.orderService = orderService;
    }
    @Override
    public void reduceStock() {
        log.info("预减库存开始……");
        orderService.reduceStock();
        log.info("预减库存结束……");
    }
}

然后是新增的权限验证代理类代码



@Slf4j
public class OrderServicePermissionProxy implements OrderService {
    //注意,这里换成了接口
    private OrderService orderService;
    public OrderServicePermissionProxy(OrderService orderService) {
        this.orderService = orderService;
    }
    @Override
    public void reduceStock() {
        log.info("权限验证开始……");
        orderService.reduceStock();
        log.info("权限验证结束……");
    }
}

测试用例


    
    @Test
    public void testOrderServiceProxy3() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        OrderServiceLogProxy2 logProxy2 = new OrderServiceLogProxy2(orderService);
        OrderServicePermissionProxy permissionProxy = new OrderServicePermissionProxy(logProxy2);
        permissionProxy.reduceStock();
    }

测试结果

16:00:28.348 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServicePermissionProxy - 权限验证开始……
16:00:28.365 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceLogProxy2 - 预减库存开始……
16:00:28.365 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceImpl - 预减库存中……
16:00:29.365 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceLogProxy2 - 预减库存结束……
16:00:29.365 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServicePermissionProxy - 权限验证结束……

接下来,如果你需要调换一下代理类逻辑执行顺序问题,你只需要在使用(像测试一样)时调换一下实例化顺序即可实现日志功能和权限验证的先后执行顺序了,而不需要像继承方式一样去不断的新建代理类。

动态代理

看完上面的静态代理,我们发现,静态代理模式的代理类,只是实现了特定类的代理,比如上面OrderServiceLogProxy实现的OrderServiceimpl的代理,如果我还有个UserService也许要日志记录、权限校验功能,又得写双份的UserServiceLogProxy、UserServicePermissionProxy代理类,里面的逻辑很多都是相同的,也就是说你代理类对象的方法越多,你就得写越多的重复的代码,那么有了动态代理就可以比较好的解决这个问题,动态代理就可以动态的生成代理类,实现对不同类下的不同方法的代理。

JDK动态代理

jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。代理类必须实现InvocationHandler接口,并且,JDK动态代理只能代理实现了接口的类,没有实现接口的类是不能实现JDK动态代理。结合下面代码来看就比较清晰了。


import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Slf4j
public class DynamicLogProxy implements InvocationHandler {
    //需要代理的对象类
    private Object target;

    public DynamicLogProxy(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
        log.info("这里是日志记录切面,日志开始……");
        //使用方法的反射
        Object invoke = method.invoke(target, args);
        log.info("这里是日志记录切面,日志结束……");
        return invoke;
    }
}

使用时代码


    
    @Test
    public void testDynamicLogProxy() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        Class<?> clazz = orderService.getClass();
        DynamicLogProxy logProxyHandler = new DynamicLogProxy(orderService);
        //通过Proxy.newProxyInstance(类加载器, 接口s, 事务处理器Handler) 加载动态代理
        OrderService os = (OrderService) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), logProxyHandler);
        os.reduceStock();
    }

输出结果

16:35:54.584 [main] INFO com.simons.cn.springbootdemo.proxy.DynamicLogProxy - 这里是日志记录切面,日志开始……
16:35:54.587 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceImpl - 预减库存中……
16:35:55.587 [main] INFO com.simons.cn.springbootdemo.proxy.DynamicLogProxy - 这里是日志记录切面,日志结束……

使用JDK动态代理类基本步骤:

1、编写需要被代理的类和接口(我这里就是OrderServiceImpl、OrderService);

2、编写代理类(例如我这里的DynamicLogProxy),需要实现InvocationHandler接口,重写invoke方法;

3、使用Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务方法。

那么这个时候,如果我需要在代理类中叠加功能,该如何是好?比如不仅要日志,还新增权限认证,思路还是上面的聚合方式实现静态代理里的那样,贴下代码,先新增权限认证代理类


import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

@Slf4j
public class DynamicPermissionProxy implements InvocationHandler{
    private Object target;
    public DynamicPermissionProxy(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
        log.info("这里是权限认证切面,开始验证……");
        Object invoke = method.invoke(target,args);
        log.info("这里是权限认证切面,结束验证……");
        return invoke;
    }
}

然后使用时候,需要稍微改动下


    
    @Test
    public void testDynamicLogAndPermissProxy() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        Class<?> clazz = orderService.getClass();
        DynamicLogProxy logProxyHandler = new DynamicLogProxy(orderService);
        OrderService os = (OrderService) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), logProxyHandler);
        //注:这里把日志代理类实例对象传入权限认证代理类中
        DynamicPermissionProxy dynamicPermissionProxy = new DynamicPermissionProxy(os);
        OrderService os2 = (OrderService)Proxy.newProxyInstance(os.getClass().getClassLoader(),os.getClass().getInterfaces(),dynamicPermissionProxy);
        os2.reduceStock();
    }

如上即可,后面还需要叠加功能代理类的话,按照上面的思路依次传入代理对象实例即可。

如何实现一个HashMap的动态代理类?


public class HashMapProxyTest {
    public static void main(String[] args) {
        final HashMap<String, Object> hashMap = new HashMap<>();
        Map<String, Object> mapProxy = (Map<String, Object>) Proxy.newProxyInstance(HashMap.class.getClassLoader(), HashMap.class.getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return method.invoke(hashMap, args);
            }
        });
        mapProxy.put("key1", "value1");
        System.out.println(mapProxy);
    }
}

Cglib动态代理

cglib是针对类来实现代理的,它会对目标类产生一个代理子类,通过方法拦截技术对过滤父类的方法调用。代理子类需要实现MethodInterceptor接口。另外,如果你是基于Spring配置文件形式开发,那你需要显示声明:


<aop:aspectj-autoproxy proxy-target-class="true"/>

如果你是基于SpringBoot开发,则一般在启动类头部显示的添加注解 


@EnableAspectJAutoProxy(proxyTargetClass = true)

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

@Slf4j
public class DynamicCglibLogProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxyObj(Class clazz) {
        //设置父类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        enhancer.setUseCache(false);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        log.info("这里是日志记录切面,日志开始……");
        //代理类对象实例调用父类方法
        Object result = methodProxy.invokeSuper(o, args);
        log.info("这里是日志记录切面,日志结束……");
        return result ;
    }
}

测试用例


    
    @Test
    public void testGClibDynamicLogProxy(){
        DynamicCglibLogProxy dynamicCglibLogProxy = new DynamicCglibLogProxy();
        OrderServiceImpl orderService = (OrderServiceImpl)dynamicCglibLogProxy.getProxyObj(OrderServiceImpl.class);
        orderService.reduceStock();
    }

输出结果

17:41:07.007 [main] INFO com.simons.cn.springbootdemo.proxy.DynamicCglibLogProxy - 这里是日志记录切面,日志开始……
17:41:07.038 [main] INFO com.simons.cn.springbootdemo.proxy.OrderServiceImpl - 预减库存中……
17:41:08.038 [main] INFO com.simons.cn.springbootdemo.proxy.DynamicCglibLogProxy - 这里是日志记录切面,日志结束……

JDK与Cglib动态代理对比?

1、JDK动态代理只能代理实现了接口的类,没有实现接口的类不能实现JDK的动态代理;

2、Cglib动态代理是针对类实现代理的,运行时动态生成被代理类的子类拦截父类方法调用,因此不能代理声明为final类型的类和方法;

动态代理和静态代理的区别?

1、静态代理在代理前就知道要代理的是哪个对象,而动态代理是运行时才知道;

2、静态代理一般只能代理一个类,而动态代理能代理实现了接口的多个类;

Spring如何选择两种代理模式的?

1、如果目标对象实现了接口,则默认采用JDK动态代理;

2、如果目标对象没有实现接口,则使用Cglib代理;

3、如果目标对象实现了接口,但强制使用了Cglib,则使用Cglib进行代理

我们可以结合源码来看下,上面的选择:

补充

Cglib实现的MethodInterceptor接口在spring-core包下,你可能需要要引入


<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>4.1.0.RELEASE</version>
</dependency>

@Slf4j是lombok里提供的,而且如果你在intellij idea开发工具中使用还需要安装lombok插件

@Test是Junit包下的,你可能需要引入


<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.11</version>
     <scope>test</scope>
</dependency>

总结

本篇文章就到这里了,希望可以给你带来一些帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: jdk动态代理和cglib动态代理详解

本文链接: https://www.lsjlt.com/news/129699.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • jdk动态代理和cglib动态代理详解
    目录静态代理基于继承的方式实现静态代理基于聚合的方式实现静态代理继承与聚合方式实现的静态代理对比动态代理JDK动态代理如何实现一个HashMap的动态代理类?Cglib动态代理JDK...
    99+
    2022-11-12
  • JDK动态代理和CGLIB区别
    JDK动态代理和CGLIB区别1、JDK动态代理:利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。(相关视频教程分享:java视频...
    99+
    2020-11-10
    java教程 JDK CGLIB 区别
  • spring cglib 与 jdk 动态代理
    1. 概述JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理Cglib动态代理是 利用asm开源包 把被代理类的class文件加载进来 通过修改其字节码生成子类来处...
    99+
    2023-05-31
    spring cglib jdk
  • 通俗易懂 快速理解 JDK动态代理 和 cglib动态代理
    动态代理的实现方案有两种,JDK动态代理和CGLIB动态代理,区别在于JDK自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。 JDK动态代理:JDK原生的实现方式,需要被代理的...
    99+
    2023-10-21
    java spring
  • java动态代理(jdk与cglib)详细解析
    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息...
    99+
    2022-11-15
    java jdk cglib
  • Java反射(JDK)与动态代理(CGLIB)详解
    目录一、反射二、动态代理1、JDK代理2、CGLIB代理3、JDK代理与CGLIB代理对比总结一、反射 概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意...
    99+
    2022-11-12
  • JDK和CGLib动态代理怎么实现
    本篇内容介绍了“JDK和CGLib动态代理怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言:动态代理是一种常用的设计模式,广泛应用...
    99+
    2023-06-02
  • 基于jdk动态代理和cglib动态代理实现及区别说明
    目录jdk动态代理和cglib动态代理实现及区别jdk动态代理实现cglib动态代理区别总结jdk动态代理和cglib动态代理实现及区别 代理模式是一种设计模式,提供了对目标对象额外...
    99+
    2023-05-19
    jdk动态代理 cglib动态代理 jdk和cglib动态代理区别
  • java jdk动态代理详解
    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理。 jdk实现动态代理一般分为三步: 1. 编写接口和实现类。 2. 写一个处理器,该...
    99+
    2022-11-15
    java jdk 动态代理
  • Java基础之动态代理Cglib详解
    目录一、前言二、服务三、代理工厂四、结果一、前言 经测试,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适...
    99+
    2022-11-12
  • java代理模式(静态代理、动态代理、cglib代理)
    目录代理模式静态代理代码接口被代理对象代理对象测试动态代理代码:接口目标对象代理对象测试cglib代理代码:目标对象代理对象测试应用总结代理模式 代理模式(Proxy Pattern...
    99+
    2022-11-12
  • Java JDK与cglib动态代理有哪些区别
    本篇内容主要讲解“Java JDK与cglib动态代理有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java JDK与cglib动态代理有哪些区别”吧!一、说明sp...
    99+
    2023-07-05
  • Spring中JDK和cglib动态代理原理的示例分析
    这篇文章给大家分享的是有关Spring中JDK和cglib动态代理原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Java代理介绍Java中代理的实现一般分为三种:JDK静态代理、JDK动态代理以及C...
    99+
    2023-06-02
  • 静态代理、jdk、cglib动态代理 搞不清? 看这个文章就懂了
    一、代理模式 代理模式是一种比较好的理解的设计模式。简单来说就是 : 我们使用代理对象来增强目标对象(target obiect),这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。将核心业务代码和非核心的公共代...
    99+
    2023-08-30
    java jdk 代理模式 面试
  • 深入浅析java 中的JDK与cglib动态代理
    这篇文章将为大家详细讲解有关深入浅析java 中的JDK与cglib动态代理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java 动态代理实例详解1.jdk动态代理 package com...
    99+
    2023-05-31
    java jdk cglib
  • Java——JDK动态代理
    1.动态代理 1.1什么是动态代理? 动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益...
    99+
    2023-08-31
    java 开发语言
  • Spring之AOP两种代理机制对比分析(JDK和CGLib动态代理)
    目录Spring AOP两种代理机制对比JDK动态代理CGLib动态代理SpringAOP两种代理原理SpringAOP代理JDK动态代理CGLIB代理两者对比使用注意总结Sprin...
    99+
    2023-05-19
    Spring AOP AOP代理机制 JDK动态代理 CGLib动态代理
  • 深入理解java动态代理的两种实现方式(JDK/Cglib)
    什么是代理模式?代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。为什么要使用代理模式?通过代理模式可以实现对...
    99+
    2023-05-31
    cglib jdk java
  • Java cglib动态代理原理分析
    目录一、cglib 动态代理示例  二、代理类分析 三、Fastclass 机制分析 本文分下面三个部分来分析cglib动态代理的原理。 cglib&n...
    99+
    2022-11-12
  • jdk动态代理使用实例详解
    目录前言为什么需要代理java中常用的代理模式一、JDK 动态代理二、cglib静态代理三、spring中代理的使用总结前言 代理模式不管是JDK,spring框架,还是日常的开发中...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作