Aop切面编程(2)--代理模式
1、代理模式的理解:不修改A对象的代码的基础上,对A代码块进行拓展。通过创建ProxyA代理对象,拓展A对象并调用A对象的核心功能;
即:不修改对象的源码基础上,创建代理对象,进行功能的附加和增强;
2、代理的分类:1)静态代理;2)动态代理(jdk,cglib);
3、静态代理:在编译的过程中就已经将代理对象、被代理对象、接口确定下来了,class文件已经生成了;
实现步骤:
1、定义一个接口及其实现类;
2、创建一个代理类同样实现这个接口
3、将目标对象注注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。
3.1)定义一个接口及方法ParentPrint:
package com.example.demo.proxy;public interface ParentPrint {void print(String content);
}
3.2)定义一个被代理的类,并实现接口ParentPrint,其中print方法就是我们需要代理的核心方法;
package com.example.demo.proxy;public class Printer implements ParentPrint {@Overridepublic void print(String content) {System.out.println(content);}
}
3.3)定义代理类,构造一个有参数的构造器,并重写print方法(其中通过传入的参数调用被代理对象的print方法)。
package com.example.demo.proxy;/*
1、首先需要代理类ProxyStaticPrinter和被代理类Printer同时实现一个共同的接口 ;
2、代理类ProxyStaticPrinter需要在构造方法中注入接口定义对象,并重写代理的方法print(前置后置处理),在其中加入注入对象的print方法;
3、实例化代理对象ProxyStaticPrinter,实例化被代理对象Printer;
4、将被代理对象通过参数注入到代理对象(ProxyStaticPrinter)有参构造器中;
5、代理对象调用处理过的方法;
*/
public class ProxyStaticPrinter implements ParentPrint {private ParentPrint parentPrint;public ProxyStaticPrinter(ParentPrint parentPrint) {this.parentPrint = parentPrint;}@Overridepublic void print(String content) {System.out.println("前置操作");parentPrint.print(content);System.out.println("后置操作");}}
3.4)测试,定义一个代理对象,将代理对象通过参数传入被代理的对象中;
//测试public static void main(String[] args) {ParentPrint parentPrint = new Printer();ParentPrint ProxyParentPrint = new ProxyStaticPrinter(parentPrint);ProxyParentPrint.print("测试");}
运行
3.5)总结:
将目标对象注注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问;
优点:被代理类无需实现接口
缺点:只能代理这个类,要想代理其他类,要想代理其他类需要写新的代理方法。
4、动态代理:动态代理包含了jdk动态代理和cglib动态代理;
4.1)jkd动态代理:
实现步骤:
1、定义一个接口及其实现类;
2、自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
3、通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;
4.1.1)定义一个接口
package com.example.demo.proxy;public interface ParentPrint {void print(String content);
}
4.1.2)定义一个接口及方法ParentPrint:
package com.example.demo.proxy;public interface ParentPrint {void print(String content);
}
4.1.3)定义一个被代理的类,并实现接口ParentPrint,其中print方法就是我们需要代理的核心方法;
package com.example.demo.proxy;public class Printer implements ParentPrint {@Overridepublic void print(String content) {System.out.println(content);}
}
4.1.4)定义一个代理类ProxyJdkPrinter并实现InvocationHandler,实现invoke方法,最终调用method.invoke(parentPrint,args);
注意该Proxy类中是静态方法,且接收的三个参数依次为:
ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的。
Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型。
InvocationHandler:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。
package com.example.demo.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*jdk动态代理:前提目标类必须有父接口(接口:ParentPrint,目标类:Printer)
1、创建ProxyJdkPrinter类,继承接口InvocationHandler创建代理类的调用处理程序;
2、同样引入代理类的参数对象private ParentPrint parentPrint;
3、实现invoke方法,最终调用method.invoke(parentPrint,args);
4、测试:
实例化代理类p1;
将p1放入代理类ProxyJdkPrinter;
通过Proxy类的WuDaInvocationHandler方法创建代理对象;
代理对象调用被代理的方法;
* */
public class ProxyJdkPrinter implements InvocationHandler {private ParentPrint parentPrint;public ProxyJdkPrinter(ParentPrint parentPrint) {this.parentPrint = parentPrint;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name = method.getName();if(name.equals("print")){System.out.println("jdk增加操作");}return method.invoke(parentPrint,args);}}
4.1.5)测试,invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法,然后 invoke() 方法代替我们去调用了被代理对象的原生方法。
public static void main(String[] args) {ParentPrint p1 = new Printer();ProxyJdkPrinter proxyJdkPrinter = new ProxyJdkPrinter(p1);//newProxyInstance:创建代理实例对象//三个参数://1、 目标类的类加载器 2、目标类的父接口 3、handlerParentPrint proxyPrint = (ParentPrint)Proxy.newProxyInstance(p1.getClass().getClassLoader(), p1.getClass().getInterfaces(), proxyJdkPrinter);proxyPrint.print("测试");}
运行
4.1.6)总结:
通过java提供的Proxy类帮我们创建代理对象,基于接口的动态代理需要利用JDK中的API,在JVM内存中动态的构建Proxy对象;
优点:可以生成所有实现接口的代理对象
缺点:JDK反射生成代理必须面向接口, 这是由Proxy的内部实现决定的。生成代理的方法中你必须指定实现类的接口,它根据这个接口来实现代理类生成的所实现的接口。
4.2)cglib动态代理:当目标没有实现类的时候,可以使用;
实现步骤:
1、定义一个类;
2、自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;
3、通过 Enhancer 类的 create()创建代理类;
4.2.1)定义一个被代理类Printer
package com.example.demo.proxy;public class Printer1 {public void print(String content) {System.out.println(content);}
}
4.2.2)定义一个代理类ProxyCglibPrinter,并实现MethodInterceptor
package com.example.demo.proxy;import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*cglib动态代理:(目标对象不需要实现接口)
实现MethodInterceptor 接口,在调用目标对象的方法时,就可以实现在调用方法之前、调用方法过程中、调用方法之后对其进行控制。
1.创建目标对象target;
2.创建interceptor对象
3.创建Enhancer对象,它以目标类和interceptor作为原料,生产出代理对象
4、enhancer设置参数setSuperclass,setCallback
5、创建代理类proxy,调用需要代理的方法;
* */
public class ProxyCglibPrinter implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {String name = method.getName();if(name.equals("print")){System.out.println("cglib增加操作");}methodProxy.invokeSuper(o,objects);return null;}}
4.2.3)测试
public static void main(String[] args) {Printer1 target = new Printer1();ProxyCglibPrinter interceptor = new ProxyCglibPrinter();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(interceptor);Printer1 proxy = (Printer1)enhancer.create();proxy.print("测试");}
运行
4.2.4)总结:
无需代理类实现接口,使用Cblib中的Enhancer来生成代理对象子类,并实现MethodInterceptor中的intercept方法,在此方法中可以实现增强功能。
如果目标对象需要实现接口,则使用JDK代理。
如果目标对象不需要实现接口,则使用Cglib代理。
5、综上所述,再次总结:
静态代理:
jdk动态代理:
cglib动态代理:
相关文章:

Aop切面编程(2)--代理模式
1、代理模式的理解:不修改A对象的代码的基础上,对A代码块进行拓展。通过创建ProxyA代理对象,拓展A对象并调用A对象的核心功能; 即:不修改对象的源码基础上,创建代理对象,进行功能的附加和增强&…...
Spring Boot(八十):Tesseract实现图片文字自动识别
1Tesseract 要实现图片转文字(OCR,Optical Character Recognition)功能,可以使用一些现有的OCR库,比如Google的Tesseract或者百度AI、阿里云OCR等云服务。 下面以Tesseract为例: Tesseract是一个开源文本识别 (OCR)引擎,是目前公认最优秀、最精确的开源OCR系统,用于…...
QT 图片处理
1.qt 图片控件 在Qt中,用于显示图片的控件主要是QLabel。以下是关于Qt图片控件的详细介绍: QLabel控件: QLabel是Qt中用于显示文本或图片的控件。在显示图片时,QLabel通过setPixmap()函数来设置要显示的图片。QPixmap代表Qt中的…...
Linux C++ 053-设计模式之模板方法模式
Linux C 053-设计模式之模板方法模式 本节关键字:Linux、C、设计模式、模板方法模式 相关库函数: 概念 模板方法模式定义了一个算法的步骤,并允许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的情况下,重新…...

【Python 项目】类鸟群:仿真鸟群
类鸟群:仿真鸟群 仔细观察一群鸟或一群鱼,你会发现,虽然群体由个体生物组成,但该群体作为一个整体似乎有它自己的生命。鸟群中的鸟在移动、飞越和绕过障碍物时,彼此之间相互定位。受到打扰或惊吓时会破坏编队…...

基于信号处理的PPG信号滤波降噪方法(MATLAB)
光电容积脉搏波PPG信号结合相关算法可以用于人体生理参数检测,如血压、血氧饱和度等,但采集过程中极易受到噪声干扰,对于血压、血氧饱和度测量的准确性造成影响。随着当今社会医疗保健技术的发展,可穿戴监测设备对于PPG信号的质量…...
新一代信息技术及应用
关于云计算的描述不正确的是( )。 A 云计算可以通过网络连接,用户通过网络接入“云”中并获得有关的服务,“云”内节点之间也通过内部的网络相连 B 云计算可以快速、按需、弹性服务,用户可以按照实际需求迅速获取或释放…...
SVN 解决冲突
SVN 解决冲突 1. 引言 在软件开发过程中,版本控制是一个至关重要的环节。SVN(Subversion)作为一个流行的版本控制系统,被广泛应用于团队协作中。然而,当多个开发者同时对同一部分代码进行修改时,冲突是不可避免的。本文将详细介绍如何在SVN中解决这些冲突,以便团队成员…...

机器人前沿--PalmE:An Embodied Multimodal Language Model 具身多模态大(语言)模型
首先解释这篇工作名称Palm-E,发表时间为2023.03,其中的Palm是谷歌内部在2022.04开发的大语言模型,功能类似ChatGPT,只是由于各种原因没有那样火起来,E是Embodied的首字母,翻译过来就是具身多模态大语言模型…...
编程语言都是哪些人开发出来的?为什么都是国外较小国家的人
编程语言都是哪些人开发出来的? 编程语言的开发者通常是来自计算机科学、软件工程、数学、物理学等领域的专家、学者和工程师。这些开发者具备深厚的编程技能、算法知识、系统设计能力以及创新思维,他们致力于创造出能够解决特定问题或满足特定需求的编…...

【前端速通系列|第二篇】Vue3前置知识
文章目录 1.前言2.包管理工具npm2.1下载node.js2.2配置 npm 镜像源2.3 npm 常用命令 3.Vite构建工具4.Vue3组件化5.Vue3运行原理 1.前言 本系列文章旨在帮助大家快速上手前端开发。 2.包管理工具npm npm 是 node.js中进行 包管理 的工具. 类似于Java中的Maven。 2.1下载nod…...
ES6 Module 的语法(十二)
ES6(ECMAScript 2015)引入了模块(Modules)的概念,使得JavaScript代码可以更容易地组织和复用。 1. export 关键字 命名导出 (Named Exports) 你可以使用 export 关键字导出多个变量、函数或类。 // module.js export…...

Redis 主从复制,哨兵与集群
目录 一.redis主从复制 1.redis 主从复制架构 2.主从复制特点 3.主从复制的基本原理 4.命令行配置 5.实现主从复制 6.删除主从复制 7.主从复制故障恢复 8.主从复制完整过程 9.主从同步优化配置 二.哨兵模式(Sentinel) 1.主要组件和概念 2.哨…...

CV05_深度学习模块之间的缝合教学(1)
1.1 在哪里缝 测试文件?() 训练文件?() 模型文件?(√) 1.2 骨干网络与模块缝合 以Vision Transformer为例,模型文件里有很多类,我们只在最后…...

【密码学】公钥密码的基本概念
在先前我写的密码学体制文章中谈到,现代密码学分为两大体制,介绍了一些有关对称密码体制诸如流密码和分组密码的内容。本文的主要内容则切换到公钥密码体制(又称非对称密码体制),简述了公钥密码体制的基本思想和应用方…...

【前端项目笔记】10 项目优化上线
项目优化上线 目标:优化Vue项目部署Vue项目(上线提供使用) 项目优化 项目优化策略: 生成打包报告:根据生成的报告发现问题并解决第三方库启用CDN:提高首屏页面的加载效率Element-UI组件按需加载路由懒加…...

Qt基础控件总结—多页面切换(QStackWidget类、QTabBar类和QTabWidget类)
QStackedWidget 类 QStackedWidget 类是在 QStackedLayout 之上构造的一个便利的部件,其使用方法与步骤和 QStackedLayout 是一样的。QStackedWidget 类的成员函数与 QStackedLayout 类也基本上是一致的,使用该类就和使用 QStackedLayout 一样。 使用该类可以参考QStackedL…...

团队融合与业务突破
结束了在上海久事集团下属公司的《团队融合与业务突破》课程,不仅探讨了团队领导力的关键技巧,更重要的是,我们从业务协同的视角,在跨团队中如何达成了共识,结合系统思考的相关内容,让大家看到跨部门冲突的…...

mybatilsplaus 常用注解
官网地址 baomidou注解配置...
vue引入sm-crypto通过sm4对文件进行加解密,用户输入密码
对文件加密并保存: import { sm4 } from sm-cryptofetch("你的文件地址") .then(response > response.blob()) .then(byteStream > {const reader2 new FileReader();reader2.onload function(event) {const arrayBuffer event.target.result;l…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...

JUC并发编程(二)Monitor/自旋/轻量级/锁膨胀/wait/notify/锁消除
目录 一 基础 1 概念 2 卖票问题 3 转账问题 二 锁机制与优化策略 0 Monitor 1 轻量级锁 2 锁膨胀 3 自旋 4 偏向锁 5 锁消除 6 wait /notify 7 sleep与wait的对比 8 join原理 一 基础 1 概念 临界区 一段代码块内如果存在对共享资源的多线程读写操作…...

SQLSERVER-DB操作记录
在SQL Server中,将查询结果放入一张新表可以通过几种方法实现。 方法1:使用SELECT INTO语句 SELECT INTO 语句可以直接将查询结果作为一个新表创建出来。这个新表的结构(包括列名和数据类型)将与查询结果匹配。 SELECT * INTO 新…...