Java——JDK动态代理

1.动态代理


1.1什么是动态代理?

动态代理(理解) 基于反射机制

举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益的最大化,此时就可以请律师帮助自己不仅完成对案件的陈述,还能争取权益最大化。那么Java中也是一样,如果要对功能进行增强就可以使用动态代理。

我们知道Spring是通过JDK或者CGLib实现动态代理的,今天我们讨论一下JDK实现动态代理的原理。

1.2动态代理的实现方式有几种?

  1. JDK动态代理
  2. CGLB动态代理

1.3动态代理的概念和优点

相比于静态代理(在静态代理中,对于类的每一个接口,我们都要单独写一个代理类),动态代理在创建代理对象上更加的灵活。

有需求,有问题,才会有解决方法和改进创新。那么产生动态代理的问题根源或者需求是什么呢?在静态代理中,由于每个接口都需要我们单独的写一个代理类,比较麻烦,因此我们就想,我们能不能写一个类,我们只需要把委托对象(目标对象),还有全部接口(共同行为,其实委托对象中就已经包含接口了)作为参数传给这个类的方法,然后这个方法就可以给我们返回一个我们想要的代理对象呢,并且这个代理对象可以给我们代理全部的共同行为,像是租房,结婚等?

  • 动态代理类的字节码在程序运行时由JAVA反射机制动态产生。会根据需要,通过反射机制,在程序运行期动态的为目标对象(委托对象)创建代理对象,无需程序员手动编写代理对象所属类的代码。
  • 动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为反射机制的使用使得可以生成任意类型的代理对象。
  • 动态代理的实现方式有两种,分别是:JDK动态代理和CGLIB动态代理。
  • 动态代理的目标对象是不固定的(也就是说把任何一个目标对象或者说是委托对象作为参数传递给生成代理对象的对象的方法,都会给我们返回一个我们想要的代理对象);使用动态代理以后,会在应用程序执行的时候,动态的创建目标对象代理对象依然会增强目标对象的行为;

2.JDK动态代理的概念和特点

先说一个需要注意的点:JDK动态代理的目标对象必须要有接口实现,也就是说:委托类必须要继承接口。

在JDK中,有一个Proxy类(名词,代理人)。Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类(对这个类的其他方法我了解的也不是很多,我们可以看JDK的在线API文档,百度搜一下好像挺多的)。这个类提供的有一个静态方法:newProxyInstance()方法。这个方法的目的就是给我们的目标对象(委托对象)返回一个代理对象。

newProxyInstance()方法需要有三个参数:

  1. 类加载器(ClassLoader对象)
  2. 接口集合(一个Interface对象的数组,就是需要代理对象代理那些共同行为,也是委托对象继承的共同行为接口)
  3. 一个InvocationHandler接口对象(当然可以是它的一个实现类对象)。这个接口中有一个invoke()方法。invoke()方法起到的作用很大,当代理对象调用共同行为方法的时候,invoke()方法就会被自动调用执行。

下面粘贴一张图片:

2.1动态代理的介绍

img

  1.  动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的,java源文件。
  2. 动态代理其实就是jdk运行期间,动态创建class字节码并加载到JVM。
  3. 动态代理的实现方式常用的有两种:使用JDK代理,与通过CGLlB动态代理。

2.2动态代理的实现

  1. jdk动态代理(理解):使用java反射包中的类和接口实现动态代理的功能,反射包java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy
  2. cglib动态代理(了解): cglib是第三方的工具库,创建代理对象
  • cglib的原理是继承,cglib通过继承目标类,创建它的子类,在子类中
    重写父类中同名的方法,实现功能的修改。
  • 因为cglib是继承,重写方法,所以要求目标类不能是fina1的,方法也不能是final的。cglib的要求目标类比较宽松,只要能继承就可以了。cglib在很多的框架中使用,
    比如mybatis,spring框架中都有使用

 

2.3CGLB动态代理

CGLB动态代理即Code Generation Library,是一个开源的第三方工具库,其原理是继承,去生成目标类的子类对象,这样对子类的功能进行增强。但是要求:目标类不能用final修饰,目标类中的方法也不能被final修饰。

2.4动态代理的效率

CGLB动态代理的效率要大于JDK动态代理的效率。

3.为什么使用JDK动态代理?

3.1代码案例:

  1. 请看如下例子,一个音乐人的本质会唱歌、会跳舞、会rap等,但是观众进入演唱会所时首先要交门票,最基本的实现方法是直接对方法进行改造,添加对应的功能。
    package com.zhao.service.impl;
    
    import com.zhao.service.Actor;
    
    public class CXK implements Actor {
    
    
        @Override
        public void sing(int money) {
    
            System.out.println("听"+money);
        }
    
        @Override
        public String dance() {
            System.out.println("吹灰舞");
    
            return "发放签名";
        }
    
        @Override
        public void rap() {
    
            System.out.println("练习时长两年");
        }
    }
    
  2. 这样操作发现出现了大量重复的代码,如果有十处、一百处需要同样的处理那么代码需要重复十次、一百次。当然我们可以把这些功能封装成一个增强方法,然后在功能方法中进行调用,但是也出现了方法的十处、一百处的调用操作,一旦增强方法名字改变,就需要完成所有调用处代码的修改。或者有一天不需要这些增强操作了,就再次需要在这十处、一百处删除方法调用。所以这种操作不适用于大型的项目开发的需求,此时我们就必须使用Java的动态代理机制。

在Java开发中如果一个类中的方法在基本功能之外需要进行功能扩充或者功能增强,如:事务控制、权限判断、日志记录等等操作,此时可以使用动态代理机制。

Java的JDK中Proxy类可以实现基于接口的动态代理,实现步骤示例如下:

  1. 因为Proxy类必须基于接口进行动态代理,所以首先创建接口,定义接口的规范,即功能方法的定义。
    package com.zhao.service;
    /**
     * 演员接口
     * 
     */
    public interface Actor {
       //唱歌
        void sing(int money);
        //跳舞
        String dance();
        //rap
        void rap();
    }
    
  2. 定义实现接口的子类,实现接口定义的方法,此方法只需要把核心功能实现即可,其他增强的操作可以在代理类中实现。
    package com.zhao.service.impl;
    
    import com.zhao.service.Actor;
    
    public class CXK implements Actor {
    
    
        @Override
        public void sing(int money) {
    
            System.out.println("听"+money);
        }
    
        @Override
        public String dance() {
            System.out.println("吹灰舞");
    
            return "发放签名";
        }
    
        @Override
        public void rap() {
    
            System.out.println("练习时长两年");
        }
    }
    
  3. 定义代理类,在代理类中对被代理对象进行方法增强。
    package com.zhao.advice;
    
    import com.zhao.service.Actor;
    import com.zhao.service.impl.CXK;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class JJGS {
        public static void main(String[] args) {
            //1.创建被代理类的对象----具体的人物cxk
            Actor cxk=new CXK();
            //2.创建代理对象--- 具体某人为上面cxk
            /**
             * ClassLoader loader:类的加载器---联系方式
             * Class<?>[] interfaces:类的接口类型---被代理人的类型
             * InvocationHandleer h:处理---我要帮你干什么
             */
            Actor jjr=(Actor) Proxy.newProxyInstance(CXK.class.getClassLoader(), CXK.class.getInterfaces(), new InvocationHandler() {
                /**
                 *
                 *  Object proxy:被代理对象的引用,系统会自动创建被代理对象的一个映射
                 * Method method:被代理对象的方法
                 * @param args
                 *Object[] args:被代理对象方法的参数
                 * 返回值是被代理对象执行后的返回值
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //被代理对象方法的执行,并获得返回值
                    Object result=null;
                    result=method.invoke(cxk,args);
    
                    System.out.println("演出后的增强:结算费用并纳税");
                    return result;
                }
            });
    
            //3.执行功能
    //        jjr.sing(5000);
            String dance = jjr.dance();
            System.out.println(dance);
    
        }
    }
    

  测试结果:

3.2基于子类的CGLib动态代理,可以使用Enhancer类完成直接对某个类进行动态代理。具体操作步骤如下:

  1. 创建被代理的类,并且定义功能方法,只需要完成核心功能即可。
    package com.zhao.service.impl;
    
    public class Actor {
        public void sing(int money) {
    
            System.out.println("听" + money);
        }
    
        public String dance(int money) {
            System.out.println("吹灰舞"+money);
    
            return "发放签名";
        }
    
        public void rap(int money) {
    
            System.out.println("练习时长两年"+money);
        }
    }
    
  2. 定义代理类,使用Enhancer创建代理对象,对被代理对象进行方法增强。
    package com.zhao.advice;
    import com.zhao.service.impl.Actor;
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class JJGss {
        public static void main(String[] args) {
            //1.被代理的对象
            Actor actor=new Actor();
            //2.使用CGLIb的Enhancer类创建代理对象
            Actor proxyActor = (Actor) Enhancer.create(Actor.class, new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    String methodName=method.getName();
                    String money=args[0];
                    Object result=null;
                    if(methodName.equals("danceAct")){
                        System.out.println("对方法执行前进性代理增强...");
                        result=method.invoke(actor,money);
                        System.out.println("对方法执行后进性代理增强...");
    
                        return result;
                    }
                    return result;
                }
            });
    
            //
            proxyActor.dance(3000);
        }
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7646.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软硬皆施,WMS仓库管理系统+PDA,实现效率狂飙

人工经验Excel表格&#xff0c;是传统第三方仓储企业常用的管理模式。在这种管理模式下&#xff0c;对仓库员工的Excel操作能力、业务经验和工作素养要求极高。一旦员工的经验能力不足&#xff0c;就会导致仓库业务运行不顺畅&#xff0c;效率低下&#xff0c;而员工也会因长时…

【MySQL】基于GTID的半同步主从复制(实践)

一、GTID简介 什么是GTID? 全局事务标识符GTID的全称为Global Transaction Identifier&#xff0c;是在整个复制环境中对一个事务的唯一标识。 它是MySQL 5.6加入的一个强大特性&#xff0c;目的在于能够实现主从自动定位和切换&#xff0c;而不像以前需要指定文件和位置。 …

ArduPilot飞控之DIY-F450计划

ArduPilot飞控之DIY-F450计划1. 历史2. 源由3. 计划3.1 硬件3.2 软件4. 动手4.1 接线4.1.1 ELRS nano接收机4.1.2 BN880 GPS模块4.1.3 Radio Telemetry4.2 配置4.2.1 选择四轴机型4.2.2 电源参数调整4.2.3 校准加速度计4.2.4 校准磁力计4.2.5 遥控器校准4.2.6 电机设置4.2.7 电…

企业电子招投标采购系统——功能模块功能描述+数字化采购管理 采购招投标

​ 功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

Melis4.0[D1s]:4.测试笔记 - 内嵌的显示命令

文章目录1.配置将显示测试源码包含进工程&#xff08;默认是包含了&#xff09;2.不要启动melis桌面系统3.开始测试3.1 disp 命令3.1.1 disp不带参数时&#xff0c;打印显示信息&#xff1a;3.1.2 disp -c 0 8 测试4种颜色3.2 disp_layer_cfg 命令3.3 disp_mem 对显示内存写入内…

全球自动驾驶竞争力最新排行榜,4家中国企业上榜

发展至今&#xff0c;自动驾驶技术不仅是汽车行业的一个主战场&#xff0c;更是全球科技领域中备受关注和充满竞争的一个重要领域。近年来&#xff0c;各大汽车制造商和科技公司都在投入大量财力物力人力进行自动驾驶技术的研发&#xff0c;并进一步争夺市场份额。 当然&#…

人工智能前沿——「小海带」超全视觉注意力机制资源分享(附下载链接)

&#x1f4da;&#x1f4da; 人工智能 | 计算机视觉 —— 致力于目标检测领域科研Tricks改进与推荐 | 主要包括主干网络改进、轻量化网络、注意力机制、检测头部改进、空间金字塔池化、损失函数及NMS改进、ICCV/CVPR/ECCV视觉顶会创新点改进、各类数据集资源分享以及算法训练相…

智云通CRM:如何给客户创造尽可能安全的成交环境?

销售人员要想和客户顺利成交&#xff0c;给对方创造尽可能安全的成交环境尤为重要。销售人员的每一句话和每一个观点&#xff0c;应当都是客户所想的。客户是非常聪明的&#xff0c;有任何风吹草动&#xff0c;他们都会提高警惕&#xff0c;这就是客户跟销售人员之间关系的现状…

笔记:关于使用vitepress 制作静态站点并托管到gitee

笔记&#xff1a;关于使用vitepress 制作静态站点并托管到giteegiteejcLee95&#xff1a;https://blog.csdn.net/qq_28550263?spm1001.2101.3001.5343 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/129419979…

spring5(五):AOP操作

spring5&#xff08;五&#xff09;&#xff1a;AOP操作前言一、代理模式1、场景模拟2、代理模式2.1 概念2.2 静态代理2.3 动态代理二、AOP概述1、什么是 AOP?2、相关术语3、作用三、AOP底层原理1、AOP 底层使用动态代理2、AOP&#xff08;JDK 动态代理&#xff09;2.1 编写 J…

二分查找(二)

2.练习题 3&#xff09; 力扣https://leetcode.cn/problems/search-in-rotated-sorted-array-ii/这题需要分三种情况&#xff0c;第一种是区间有序&#xff0c;正常二分查找&#xff0c;第二种是区间 被旋转&#xff0c;左区间的值大于右区间&#xff0c;需要比较目标值和左区…

机器视觉行业公司2023今年最大的特点-老员工真香现象出现,事出反常必有妖

老员工真香现象出现&#xff0c;事出反常必有妖。-老人涨薪&#xff0c;新人不招或降薪&#xff0c;工作2-3年最值得跳槽&#xff0c;培训后好找工作。 你可能看到以上现象很反感&#xff0c;但是现在机器视觉行业环境就是这个样子的。 今年机器视觉行业最大的特点就是项目技术…

Atlassian Server用户新选择 | 迁移到数据中心版前,您需要做这些准备(2)

2024年2月&#xff0c;也就是一年不到&#xff0c;Atlassian将终止对Server产品及插件的所有支持。 此公告发布后&#xff0c;许多用户需要了解怎样的前进方向才是最适合企业的。为此&#xff0c;Atlassian不仅提供云版&#xff0c;还提供了本地部署的数据中心&#xff08;Data…

排序算法之希尔排序

&#x1f4dd;个人主页&#xff1a;爱吃炫迈 &#x1f48c;系列专栏&#xff1a;数据结构与算法 &#x1f9d1;‍&#x1f4bb;座右铭&#xff1a;快给我点赞赞&#x1f497; 文章目录1. 希尔排序2. 算法思路3. 算法实现4. 算法性能分析&#x1f49e;总结&#x1f49e;1. 希尔排…

帆软FineReport学习篇(一)

帆软FineReport学习篇(一) 1 FineReport 11版下载 1.1 进入下载官网 fineReport 11版本下载链接 1.2 选择合适的版本,点击下载即可 2 解决问题的途径 2.1 社区搜索 2.1.1 进入社区官网 社区官网 2.1.2 输入搜索内容,点击搜索 1.1.3 选择你所需要的答案,建议优先点击官方…

易基因-单细胞甲基化测序单细胞转录组测序

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 易基因单细胞甲基化测序&单细胞转录组测序 高通量单细胞DNA甲基化测序简介 单细胞DNA甲基化组学研究很大程度上受制于建库技术&#xff0c;传统的文库构建方法或类似于基因组DNA的单…

【Python】1分钟就能制作精美的框架图?太棒啦

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、准备二、基本使用与例子1.初始化与导出2.节点类型3.集群块4.自定义线的颜色与属性总结前言 Diagrams 是一个基于Python绘制云系统架构的模块&#xff0c;它能…

使用Pytorch实现对比学习SimCLR 进行自监督预训练

SimCLR&#xff08;Simple Framework for Contrastive Learning of Representations&#xff09;是一种学习图像表示的自监督技术。 与传统的监督学习方法不同&#xff0c;SimCLR 不依赖标记数据来学习有用的表示。 它利用对比学习框架来学习一组有用的特征&#xff0c;这些特征…

linux 匿名管道 pipe

专栏内容&#xff1a;linux下并发编程个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e;目录 前言 概述 原理介绍 接口说明 pipe 与 fifo的区别 代码演示 结尾 前言 本专栏主…

【K8S系列】深入解析无状态服务

目录 序言 1. 无服务介绍 1.1 优点 1.2 使用场景 1.3 资源类型 1.4 总结 2 使用介绍 2.1 Deployment 使用场景&#xff1a; 2.2 ReplicaSet 使用场景 2.3 pod Pod 资源定义示例 2.4 service 创建一个Deployment&#xff1a; 创建一个Service&#xff1a; 总结…