05-代理模式
代理模式
代理模式使用代理对象来代替真实对象的访问,在不修改原有对象的前提下,提供额外的操作,扩展目标对象的功能。代理模式分为静态代理和动态代理。
静态代理
手动为目标对象中的方法进行增强,通过实现相同接口重写方法进行增强。非常不灵活,当对象中新增方法时,代理类同样需要增加代理方法。静态代理是在代码编译时生成的代理类
实现步骤
- 定义接口和实现类
- 定义代理类实现接口
- 将被代理类注入,重写方法,在方法中增强
代码展示
-
接口
public interface Image {void display(String name); } -
实现类
public class RealImage implements Image {@Overridepublic void display(String name) {System.out.println(name + " display");} } -
代理类
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 个参数:
- loader :类加载器,用于加载代理对象。
- interfaces : 被代理类实现的一些接口;
- h : 实现了
InvocationHandler接口的对象;
要实现动态代理的话,还必须需要实现InvocationHandler 来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现InvocationHandler 接口类的 invoke 方法来调用。
public interface InvocationHandler {/*** 当你使用代理对象调用方法的时候实际会调用到这个方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
invoke() 方法有下面三个参数:
- proxy :动态生成的代理类
- method : 与代理类对象调用的方法相对应
- args : 当前 method 方法的参数
实现步骤
- 定义接口和实现类
- 自定义**
InvocationHandler并重写invoke**方法,在方法中调用被代理的方法并实现自定义处理逻辑 - 通过
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法创建代理对象 - 使用代理对象进行方法调用
代码展示
-
接口和实现类同上
-
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;} } -
代理对象生成
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));}} -
测试
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;
}
- obj : 被代理的对象(需要增强的对象)
- method : 被拦截的方法(需要增强的方法)
- args : 方法入参
- proxy : 用于调用原始方法
你可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。
实现步骤
- 实现类
- 自定义
MethodInterceptor并重写intercept方法,自定义增强逻辑 - 通过
Enhancer中的create()方法创建代理对象 - 使用代理对象调用方法
代码展示
-
实现类
public class RealImage2 {public void display(String name) {System.out.println(name + " display");} } -
自定义
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;} } -
通过
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();} } -
使用
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-代理模式
代理模式 代理模式使用代理对象来代替真实对象的访问,在不修改原有对象的前提下,提供额外的操作,扩展目标对象的功能。代理模式分为静态代理和动态代理。 静态代理 手动为目标对象中的方法进行增强,通过实现相同接口重写方法进…...
RocketMQ源码分析之消费队列、Index索引文件存储结构与存储机制-上篇
RocketMQ 存储基础回顾: 源码分析RocketMQ之CommitLog消息存储机制 本文主要从源码的角度分析 Rocketmq 消费队列 ConsumeQueue 物理文件的构建与存储结构,同时分析 RocketMQ 索引文件IndexFile 文件的存储原理、存储格式以及检索方式。RocketMQ 的存储…...
基于Java的浏览器的设计与实现毕业设计
技术:Java等摘要:当今世界是一个以计算机网络为核心的信息时代,互联网为人们快速获取、发布和传递信息提供了便捷,而浏览器作为互联网上查找信息的重要工具,给人们提供了巨大而又宝贵的信息财富,受到了大家…...
手把手教你使用vite打包自己的js代码包并推送到npm
准备 要有npm账号,没有的铁子去npm官网注册一个,又不要钱。 使用vite创建项目 一行代码搞定 npm create vite viet-demo框架选择Others 模板选择library 选择ts 这样项目就创建完了 这个项目默认有一个函数,用来记录按钮的点击次数并…...
Tomcat源码分析-关于tomcat热加载的一些思考
在前面的文章中,我们分析了 tomcat 类加载器的相关源码,也了解了 tomcat 支持类的热加载,意味着 tomcat 要涉及类的重复卸装/装载过程,这个过程是很敏感的,一旦处理不当,可能会引起内存泄露 卸载类 我们知…...
DataWhale 大数据处理技术组队学习task4
五、分布式并行编程模型MapReduce 1. 概述 1.1 分布式并行编程 背景:摩尔定律已经开始逐渐失效,提升数据处理计算能力刻不容缓。传统的程序开发与分布式并行编程 传统的程序开发:以单指令、单数据流的方式顺序执行,虽然这种方式…...
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获取弹幕的两种方式(一种简单但量少,另一量大管饱)
前言 弹幕可以给观众一种“实时互动”的错觉,虽然不同弹幕的发送时间有所区别,但是其只会在视频中特定的一个时间点出现,因此在相同时刻发送的弹幕基本上也具有相同的主题,在参与评论时就会有与其他观众同时评论的错觉。 在国内…...
算法训练营 day55 动态规划 买卖股票问题系列3
算法训练营 day55 动态规划 买卖股票问题系列3 最佳买卖股票时机含冷冻期 309. 最佳买卖股票时机含冷冻期 - 力扣(LeetCode) 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下…...
电商共享购模式,消费增值返利,app开发
在当今以市场需求为主导的数字经济时代,消费者需求呈现出精细化管理和多元化的特性,目标市场日渐完善,另外在大数据技术迅速进步和运用的驱动下,总体行业的发展节奏感也在不断加速。因而,企业需要建立一套灵活多变的经…...
机房信息牌系统
产品特色: 无线低功耗安装简单,快速布置易于维护墨水屏显示,清晰,更环保信息后台推送,远程管理多模版样式随意制作多尺寸:4.2寸,7.5寸,10.2寸4.2寸7.5寸10.2寸标签特性:…...
金测评 手感更细腻的游戏手柄,双模加持兼容更出色,雷柏V600S上手
很多朋友周末都喜欢玩玩游戏放松一下,在家玩游戏的时候,PC是大家常用的平台,当然了,玩游戏的时候用键鼠的话,手感难免差点意思,还是要手柄才能获得更好的体验。我现在用的是雷柏V600S,这是一款支…...
Windows10 下测试 Intel SGX 功能
文章目录参考文献系统要求一、安装Open Enclave SDK 环境(一)什么是Open Enclave SDK(二)启动SGX功能方法一: BIOS启动方法二:软件方式启动(三)安装必要环境(1࿰…...
Tina_Linux_功耗管理_开发指南
Tina Linux 功耗管理开发指南 1 概述 1.1 编写目的 简要介绍tina 平台功耗管理机制,为关注功耗的开发者,维护者和测试者提供使用和配置参考。 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的共享汽车管理系统
文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏…...
TCP三次握手
参考:4.1 TCP 三次握手与四次挥手面试题 | 小林coding TCP 头格式 我们先来看看 TCP 头的格式,标注颜色的表示与本文关联比较大的字段,其他字段不做详细阐述。 序列号:在建立连接时由计算机生成的随机数作为其初始值,…...
未来土地利用模拟FLUS模型
未来土地利用模拟(FutureLand-Use Simulation, FLUS)模型1 模型简介1.1 基于ANN 的适宜性概率计算1.2 基于自适应惯性机制的元胞自动机1.3 模拟精度评价参考流域 径流变化是 自然因素和 人为因素共同作用的结果,其中人为因素最为直接的方式就…...
压力传感器MPX5700D/MPX5700GP/MPX5700AP产品概述、特征
MPX5700系列压阻式换能器是最先进的单片硅压力传感器,可广泛用于各种应用,特别是采用A/D输入微控制器或微处理器的应用。这一获得专利的单元件传感器集合了高级微加工技术、薄膜金属化、双极工艺,能够提供精确的、与所施加压力成正比的高电平…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
