当前位置: 首页 > news >正文

05-代理模式

代理模式

代理模式使用代理对象来代替真实对象的访问,在不修改原有对象的前提下,提供额外的操作,扩展目标对象的功能。代理模式分为静态代理动态代理

静态代理

手动为目标对象中的方法进行增强,通过实现相同接口重写方法进行增强。非常不灵活,当对象中新增方法时,代理类同样需要增加代理方法。静态代理是在代码编译时生成的代理类

实现步骤

  1. 定义接口和实现类
  2. 定义代理类实现接口
  3. 将被代理类注入,重写方法,在方法中增强

代码展示

  1. 接口

    public interface Image {void display(String name);
    }
    
  2. 实现类

    public class RealImage implements Image {@Overridepublic void display(String name) {System.out.println(name + " display");}
    }
    
  3. 代理类

    public class StaticProxy implements Image {private RealImage realImage;@Overridepublic void display(String name) {realImage = new RealImage();System.out.println("start");realImage.display(name);System.out.println("end");}public static void main(String[] args) {Image image = new StaticProxy();image.display("图片");}
    }
    

静态代理简单并且局限性太高,一般没有人使用

动态代理

相较于静态代理,动态代理更加灵活,可以被多个类创建统一代理类。针对实现类和接口分别有JDK动态代理CGLIB动态代理。动态代理是在运行时动态生成代理类并加载到JVM中去的。

JDK动态代理

JDK动态代理是为已经实现接口的类创建代理类。核心是**InvocationHandler接口和Proxy类。Proxy类用于生成代理对象,InvocationHandler接口用于自定义处理逻辑。当我们用Proxy类中的newProxyInstance()方法生成的动态代理对象调用方法时,这个方法的调用会转发到InvocationHandler接口中的invoke**方法中来调用。

Proxy 类中使用频率最高的方法是:newProxyInstance() ,这个方法主要用来生成一个代理对象。

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{......}

这个方法一共有 3 个参数:

  1. loader :类加载器,用于加载代理对象。
  2. interfaces : 被代理类实现的一些接口;
  3. h : 实现了 InvocationHandler 接口的对象;

要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。

public interface InvocationHandler {/*** 当你使用代理对象调用方法的时候实际会调用到这个方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

invoke() 方法有下面三个参数:

  1. proxy :动态生成的代理类
  2. method : 与代理类对象调用的方法相对应
  3. args : 当前 method 方法的参数

实现步骤

  1. 定义接口和实现类
  2. 自定义**InvocationHandler并重写invoke**方法,在方法中调用被代理的方法并实现自定义处理逻辑
  3. 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象
  4. 使用代理对象进行方法调用

代码展示

  1. 接口和实现类同上

  2. InvocationHandler

    /*** @author linmeng* @date 2023/2/22 00:42*/
    public class JdkInvocationHandler implements InvocationHandler {/*** 被代理类**/private Object target;public JdkInvocationHandler(Object target) {this.target = target;}/*** @Author linmeng* @Description * @date 2023/2/24 15:57* @param proxy 动态生成的代理类* @param method 代理方法* @param args 方法参数* @return java.lang.Object**/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("调用方法前打印方法名称;" + method.getName());Object res = method.invoke(target, args);System.out.println("调用方法后打印方法名称;" + method.getName());return res;}
    }
    
  3. 代理对象生成

    import java.lang.reflect.Proxy;/*** @author linmeng* @date 2023/2/22 00:44*/
    public class JDKProxy {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new JdkInvocationHandler(target));}}
    
  4. 测试

    import org.junit.Test;/*** @author linmeng* @date 2023/2/22 00:50*/public class JdkTest {@Testpublic void jdkTest(){Image proxy = (Image) JDKProxy.getProxy(new RealImage());proxy.display("图片");}
    

CGLIB动态代理

当类没有实现接口时,是不能用JDK动态代理的。这个时候可以用CGLIB动态代理,他是通过继承的方式实现代理。

**在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心。**通过实现MethodInterceptor接口中的intercept方法自定义处理逻辑,Enhancer类创建代理类。

你需要自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法。

public interface MethodInterceptor
extends Callback{// 拦截被代理类中的方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
  1. obj : 被代理的对象(需要增强的对象)
  2. method : 被拦截的方法(需要增强的方法)
  3. args : 方法入参
  4. proxy : 用于调用原始方法

你可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

实现步骤

  1. 实现类
  2. 自定义MethodInterceptor 并重写 intercept方法,自定义增强逻辑
  3. 通过 Enhancer中的create()方法创建代理对象
  4. 使用代理对象调用方法

代码展示

  1. 实现类

    public class RealImage2 {public void display(String name) {System.out.println(name + " display");}
    }
    
  2. 自定义MethodInterceptor 并重写 intercept方法

    /*** @author linmeng* @date 2023/2/24 14:10*/
    public class CGLIBInterceptor implements MethodInterceptor {/*** @param o           被代理对象* @param method      被拦截的方法* @param objects     方法入参* @param methodProxy 用于调用元素方法* @return java.lang.Object* @Author linmeng* @Description* @date 2023/2/24 14:11**/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("调用方法前打印方法名称;" + method.getName());Object res = methodProxy.invokeSuper(o, objects);System.out.println("调用方法后打印方法名称;" + method.getName());return res;}
    }
    
  3. 通过 Enhancer中的create()方法创建代理对象

    import net.sf.cglib.proxy.Enhancer;/*** @author linmeng* @date 2023/2/24 14:15*/
    public class CGLIBProxy {public static Object getProxy(Class<?> clazz) {// 动态代理增强类Enhancer enhancer = new Enhancer();// 类加载器enhancer.setClassLoader(clazz.getClassLoader());// 被代理类enhancer.setSuperclass(clazz);// 增强类enhancer.setCallback(new CGLIBInterceptor());// 代理类创建return enhancer.create();}
    }
    
  4. 使用

    import org.junit.Test;/*** @author linmeng* @date 2023/2/22 00:50*/
    public class CGLIBTest {@Testpublic void cglibTest(){RealImage2 proxy = (RealImage2) CGLIBProxy.getProxy(RealImage2.class);proxy.display("图片");}
    }
    

参考链接

  • Java设计模式:Proxy(代理)模式
  • Java 代理模式详解
  • Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass

相关文章:

05-代理模式

代理模式 代理模式使用代理对象来代替真实对象的访问&#xff0c;在不修改原有对象的前提下&#xff0c;提供额外的操作&#xff0c;扩展目标对象的功能。代理模式分为静态代理和动态代理。 静态代理 手动为目标对象中的方法进行增强&#xff0c;通过实现相同接口重写方法进…...

RocketMQ源码分析之消费队列、Index索引文件存储结构与存储机制-上篇

RocketMQ 存储基础回顾&#xff1a; 源码分析RocketMQ之CommitLog消息存储机制 本文主要从源码的角度分析 Rocketmq 消费队列 ConsumeQueue 物理文件的构建与存储结构&#xff0c;同时分析 RocketMQ 索引文件IndexFile 文件的存储原理、存储格式以及检索方式。RocketMQ 的存储…...

基于Java的浏览器的设计与实现毕业设计

技术&#xff1a;Java等摘要&#xff1a;当今世界是一个以计算机网络为核心的信息时代&#xff0c;互联网为人们快速获取、发布和传递信息提供了便捷&#xff0c;而浏览器作为互联网上查找信息的重要工具&#xff0c;给人们提供了巨大而又宝贵的信息财富&#xff0c;受到了大家…...

手把手教你使用vite打包自己的js代码包并推送到npm

准备 要有npm账号&#xff0c;没有的铁子去npm官网注册一个&#xff0c;又不要钱。 使用vite创建项目 一行代码搞定 npm create vite viet-demo框架选择Others 模板选择library 选择ts 这样项目就创建完了 这个项目默认有一个函数&#xff0c;用来记录按钮的点击次数并…...

Tomcat源码分析-关于tomcat热加载的一些思考

在前面的文章中&#xff0c;我们分析了 tomcat 类加载器的相关源码&#xff0c;也了解了 tomcat 支持类的热加载&#xff0c;意味着 tomcat 要涉及类的重复卸装/装载过程&#xff0c;这个过程是很敏感的&#xff0c;一旦处理不当&#xff0c;可能会引起内存泄露 卸载类 我们知…...

DataWhale 大数据处理技术组队学习task4

五、分布式并行编程模型MapReduce 1. 概述 1.1 分布式并行编程 背景&#xff1a;摩尔定律已经开始逐渐失效&#xff0c;提升数据处理计算能力刻不容缓。传统的程序开发与分布式并行编程 传统的程序开发&#xff1a;以单指令、单数据流的方式顺序执行&#xff0c;虽然这种方式…...

Oracle 12C以上统计信息收集CDB、PDB执行时间不一致问题

文章目录前言一、统计信息窗口期调查二、时区调查三、查询alert记录四、why Database Statistic Collection Job is running two times inside a Maintenance Window?五、Default Scheduler Timezone Value In PDB$SEED Different Than CDB六、总结前言 在实际工作中发现一个…...

用Python获取弹幕的两种方式(一种简单但量少,另一量大管饱)

前言 弹幕可以给观众一种“实时互动”的错觉&#xff0c;虽然不同弹幕的发送时间有所区别&#xff0c;但是其只会在视频中特定的一个时间点出现&#xff0c;因此在相同时刻发送的弹幕基本上也具有相同的主题&#xff0c;在参与评论时就会有与其他观众同时评论的错觉。 在国内…...

算法训练营 day55 动态规划 买卖股票问题系列3

算法训练营 day55 动态规划 买卖股票问题系列3 最佳买卖股票时机含冷冻期 309. 最佳买卖股票时机含冷冻期 - 力扣&#xff08;LeetCode&#xff09; 给定一个整数数组prices&#xff0c;其中第 prices[i] 表示第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下…...

电商共享购模式,消费增值返利,app开发

在当今以市场需求为主导的数字经济时代&#xff0c;消费者需求呈现出精细化管理和多元化的特性&#xff0c;目标市场日渐完善&#xff0c;另外在大数据技术迅速进步和运用的驱动下&#xff0c;总体行业的发展节奏感也在不断加速。因而&#xff0c;企业需要建立一套灵活多变的经…...

机房信息牌系统

产品特色&#xff1a; 无线低功耗安装简单&#xff0c;快速布置易于维护墨水屏显示&#xff0c;清晰&#xff0c;更环保信息后台推送&#xff0c;远程管理多模版样式随意制作多尺寸&#xff1a;4.2寸&#xff0c;7.5寸&#xff0c;10.2寸4.2寸7.5寸10.2寸标签特性&#xff1a;…...

金测评 手感更细腻的游戏手柄,双模加持兼容更出色,雷柏V600S上手

很多朋友周末都喜欢玩玩游戏放松一下&#xff0c;在家玩游戏的时候&#xff0c;PC是大家常用的平台&#xff0c;当然了&#xff0c;玩游戏的时候用键鼠的话&#xff0c;手感难免差点意思&#xff0c;还是要手柄才能获得更好的体验。我现在用的是雷柏V600S&#xff0c;这是一款支…...

Windows10 下测试 Intel SGX 功能

文章目录参考文献系统要求一、安装Open Enclave SDK 环境&#xff08;一&#xff09;什么是Open Enclave SDK&#xff08;二&#xff09;启动SGX功能方法一&#xff1a; BIOS启动方法二&#xff1a;软件方式启动&#xff08;三&#xff09;安装必要环境&#xff08;1&#xff0…...

Tina_Linux_功耗管理_开发指南

Tina Linux 功耗管理开发指南 1 概述 1.1 编写目的 简要介绍tina 平台功耗管理机制&#xff0c;为关注功耗的开发者&#xff0c;维护者和测试者提供使用和配置参考。 1.2 适用范围 表1-1: 适用产品列表产品名称内核版本休眠类型参与功耗管理的协处理器R328Linux-4.9NormalS…...

golang编译dll失败问题解决

执行go build -buildmodec-shared -o exportgo.dll exportgo.go报类似如下错误/usr/lib/gcc/x86_64-pc-msys/9.1.0/../../../../x86_64-pc-msys/bin/ld: 找不到 -lmingwex/usr/lib/gcc/x86_64-pc-msys/9.1.0/../../../../x86_64-pc-msys/bin/ld: 找不到 -lmingw32安装tdm gcc m…...

Convolutional Neural Networks for Sentence Classification

摘要 We report on a series of experiments with convolutional neural networks (CNN) trained on top of pre-trained word vectors for sentence-level classification tasks. We show that a simple CNN with little hyperparameter tuning and static vectors achieves e…...

基于SpringBoot的共享汽车管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…...

TCP三次握手

参考&#xff1a;4.1 TCP 三次握手与四次挥手面试题 | 小林coding TCP 头格式 我们先来看看 TCP 头的格式&#xff0c;标注颜色的表示与本文关联比较大的字段&#xff0c;其他字段不做详细阐述。 序列号&#xff1a;在建立连接时由计算机生成的随机数作为其初始值&#xff0c…...

未来土地利用模拟FLUS模型

未来土地利用模拟&#xff08;FutureLand-Use Simulation, FLUS&#xff09;模型1 模型简介1.1 基于ANN 的适宜性概率计算1.2 基于自适应惯性机制的元胞自动机1.3 模拟精度评价参考流域 径流变化是 自然因素和 人为因素共同作用的结果&#xff0c;其中人为因素最为直接的方式就…...

压力传感器MPX5700D/MPX5700GP/MPX5700AP产品概述、特征

MPX5700系列压阻式换能器是最先进的单片硅压力传感器&#xff0c;可广泛用于各种应用&#xff0c;特别是采用A/D输入微控制器或微处理器的应用。这一获得专利的单元件传感器集合了高级微加工技术、薄膜金属化、双极工艺&#xff0c;能够提供精确的、与所施加压力成正比的高电平…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统

Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

高分辨率图像合成归一化流扩展

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 1 摘要 我们提出了STARFlow&#xff0c;一种基于归一化流的可扩展生成模型&#xff0c;它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流&#xff08;TARFlow&am…...

动态规划-1035.不相交的线-力扣(LeetCode)

一、题目解析 光看题目要求和例图&#xff0c;感觉这题好麻烦&#xff0c;直线不能相交啊&#xff0c;每个数字只属于一条连线啊等等&#xff0c;但我们结合题目所给的信息和例图的内容&#xff0c;这不就是最长公共子序列吗&#xff1f;&#xff0c;我们把最长公共子序列连线起…...