SpringAOP前置——代理模式

代理模式是SpringAOP(面向切面编程)的底层原理

代理模式的分类

  • 静态代理
  • 动态代理

静态代理

角色分析:
抽象角色:一般使用抽象类或接口来解决
代理角色:代理真实角色,在代理真实角色后,一般会做一些附属操作
真实角色:被代理的角色
客户:访问代理对象的角色,可以理解为一个处理事务的线程,多为一次业务处理

以租房举例子进行理解

房东有房子要出租,将房源信息告诉中介,也就是让中介代理房东进行房屋租赁这件事。房东是真实角色(被代理的角色),中介是代理角色,房屋租赁这件事是抽象角色。
租房者是客户,相当于一次租房业务。
接下来上代码
抽象角色:房屋租赁这件事

package com.zbt.proxy.demo01;/*** @author* @createAt 2025/1/12 20:58*//*** 租房 接口*/
public interface Rent {//出租事件 出租的是房子 对应着一个房东void rent(Host host);
}

真实角色:房东 有两个属性 一个名字,一个房屋地址

package com.zbt.proxy.demo01;/*** @author* @createAt 2025/1/12 20:59*//*** 房东*/
public class Host implements Rent{private String name;private String address;public Host() {}public Host(String name, String address) {this.name = name;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public void rent(Host host) {System.out.println("我是房东:"+name+",我要出租房子,地址是:"+address);}
}

代理角色:中介

package com.zbt.proxy.demo01;/*** @author* @createAt 2025/1/12 21:01*/import java.util.ArrayList;
import java.util.List;/*** 中介 代理租房*/
public class Proxy implements Rent{//被代理的对象 对于中介来说就是一个房东private Host;public void setHost(Host host){hostLs.add(host);}public Host getHost(){return host;}public void rent(Host host) {//中介知道房东要出租房子  也就是中介对于你来说 代理了这套房子的房东host.rent(host);//带你去看房子seeHouse(host);//你看中了房子 签合同hetong();//中介收了中介服务费fare();}public void seeHouse(Host host){System.out.println("中介带你看了在"+host.getAddress()+"的房子");}public void hetong(){System.out.println("签租赁合同");}public void fare(){System.out.println("收中介费");}}

客户:你 你要租房子 触发了一次租房业务流程(main方法)

package com.zbt.proxy.demo01;/*** @author* @createAt 2025/1/12 21:00*//*** 租客要租房*/
public class Client {public static void main(String[] args) {//被代理对象 -- 房东Host host1 = new Host("房东1号","南京南街5-5-1号");//代理对象 -- 中介Proxy proxy;= new Proxy();//房东在中介登记房子proxy.setHostLs(host3);//你要租房子  找到了中介 触发了租房流程//中介给你介绍了一套房子Host host = proxy.getHostLs(0);//中介带你走租房流程  看房 签合同proxy.rent(host);}
}

静态代理模式的好处

  • 可以使真实角色的“动作”更加纯粹:例如上面的例子,房东就只需要找中介登记一下房源,就可以等着房子出租出去了,不需要进行公共业务(带人看房,贴租房广告等)
  • 公共业务交给代理角色来进行,进行过了业务的分工,
  • 在公共业务需要进行扩展的时候方便集中管理,只需要改代理对象就可以了。
    静态代理模式缺点
    一个真实角色就会产生一个代理角色,代码量会增加,开发效率降低

模拟实际开发逻辑理解静态代理

实际开发经常用到用户信息的增删查改
我们通常的写法是:

package com.zbt.proxy.demo02;/*** 接口类*/
public interface UserService {void insert();void delete();void update();void select();
}package com.zbt.proxy.demo02;/*** @author* @createAt 2025/1/12 22:01*//*** 实现类*/
public class UserServiceImpl implements UserService{public void insert() {System.out.println("插入了一个用户");}public void delete() {System.out.println("删除了一个用户");}public void update() {System.out.println("修改了一个用户");}public void select() {System.out.println("查询了一个用户");}
}package com.zbt.proxy.demo02;/*** 调用* @author* @createAt 2025/1/12 22:02*/public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();userService.insert();}
}

这样当然可以实现业务需求,但是当后期,如果在此基础上需要增加新的需求时,就得修改原有的业务逻辑代码,例如在调用每个方法时,增加一条日志记录,我们就需要去修改原来的UserServiceImpl 里面每一个方法,添加一条打印语句。如果需要进行的改较为复杂,那么修改原业务逻辑是致命的,此时我们将写法改为静态代理模式。
在原有基础上,增加一个代理类UserServiceProxy 代理UserServiceImpl

package com.zbt.proxy.demo02;/*** 代理类  代理UserServiceImpl  将UserServiceImpl 对象通过set方法传入 里面直接通过UserServiceImpl 对象调用对应方法,需要修改逻辑时,直接修改代理类,例如上面提到的增加一条调用日志打印* @author* @createAt 2025/1/12 22:03*/public class UserServiceProxy implements UserService{private UserServiceImpl userService;public UserServiceImpl getUserService() {return userService;}public void setUserService(UserServiceImpl userService) {this.userService = userService;}public void insert() {log("insert");userService.insert();}public void delete() {log("delete");userService.delete();}public void update() {log("update");userService.update();}public void select() {log("select");userService.select();}//日志打印方法public void log(String msg){System.out.println("调用了"+msg+"方法");}
}package com.zbt.proxy.demo02;/*** 调用* @author* @createAt 2025/1/12 22:02*/public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy proxy = new UserServiceProxy();proxy.setUserService(userService);proxy.insert();}
}

动态代理

  • 动态代理和静态代理角色分类一样
  • 动态代理的代理类是动态生成的,不是提前写好的
  • 动态代理分为两大类:基于接口的动态代理(JDK的动态代理)、基于类的动态代理(cglib)
    两个关键的类:Proxy、InvocationHandler
  • Proxy用来生成动态代理实例
  • InvocationHandler用来调用处理程序并返回结果
    上代码:还是上面用户信息的增删查改的例子
package com.zbt.proxy.demo03;/*** 接口类*/
public interface UserService {void insert();void delete();void update();void select();
}
package com.zbt.proxy.demo03;/*** @author* @createAt 2025/1/12 22:01*//*** 实现类*/
public class UserServiceImpl implements UserService {public void insert() {System.out.println("插入了一个用户");}public void delete() {System.out.println("删除了一个用户");}public void update() {System.out.println("修改了一个用户");}public void select() {System.out.println("查询了一个用户");}
}
package com.zbt.proxy.demo03;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 动态获得代理类的工具类* @author* @createAt 2025/1/13 21:04*/
public class ProxyInvocationHandler implements InvocationHandler {//被代理的接口——真实对象private Object target;public void setTarget(Object target) {this.target = target;}//生成得到代理类实例public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), this);}//处理代理实例 并返回结果public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log(method.getName());//method.getName() 获取调用的方法名return method.invoke(target, args);}public void log(String msg){System.out.println("调用了"+msg+"方法");}
}
package com.zbt.proxy.demo03;import com.zbt.proxy.demo02.UserServiceProxy;/*** @author* @createAt 2025/1/12 22:02*/public class Client {public static void main(String[] args) {//真实角色UserServiceImpl userService = new UserServiceImpl();//代理角色 原本并不存在的类,动态生成的类ProxyInvocationHandler handler = new ProxyInvocationHandler();handler.setTarget(userService);//生成动态代理类UserService proxy = (UserService)handler.getProxy();//调用方法proxy.insert();}
}

这个动态代理我也没太理解。。。。等我再研究研究,应该就是利用反射的机制,借用Proxy、InvocationHandler来动态生成代理类

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【RDMA学习笔记】1:RDMA(Remote Direct Memory Access)介绍

从帝国理工的PPT学习。 什么是RDMA Remote Direct Memory Access,也就是Remote的DMA,是一种硬件机制,能直接访问远端结点的内存,而不需要处理器介入。 其中: Remote:跨node进行数据传输Direct&#xff…

Docker

1. 初始Docker 1.1. 什么是Docker? 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署,环…

Deep4SNet: deep learning for fake speech classification

Deep4SNet:用于虚假语音分类的深度学习 摘要: 虚假语音是指即使通过人工智能或信号处理技术产生的语音记录。生成虚假录音的方法有"深度语音"和"模仿"。在《深沉的声音》中,录音听起来有点合成,而在《模仿》中…

Navicat Premium 原生支持阿里云 PolarDB 数据库

近日,我司旗下的 Navicat Premium 软件通过了阿里云 PolarDB 数据库产品生态集成认证,这标志着 Navicat 通过原生技术全面实现了对秒级弹性、高性价比、稳定可靠的PolarDB 数据库三大引擎(PolarDB MySQL版、PolarDB PostgreSQL版和 PolarDB f…

LabVIEW光流算法的应用

该VI展示了如何使用NI Vision Development Module中的光流算法来计算图像序列中像素的运动矢量。通过该方法,可以实现目标跟踪、运动检测等功能,适用于视频处理、机器人视觉和监控领域。程序采用模块化设计,包含图像输入、算法处理、结果展示…

JAVA:在IDEA引入本地jar包的方法(不读取maven目录jar包)

问题: 有时maven使用的jar包版本是最新版,但项目需要的是旧版本,每次重新install会自动将mavan的jar包覆盖到项目的lib目录中,导致项目报错。 解决: 在IDEA中手动配置该jar包对应的目录。 点击菜单File->Projec…

升级 SpringBoot3 全项目讲解 — 为什么 SpringBoot3 应该抛弃 Maven,搭配 Gradle 来使用?

学会这款 🔥全新设计的 Java 脚手架 ,从此面试不再怕! 随着 Spring Boot 3 的发布,许多开发者开始考虑如何将现有项目升级到最新版本。Spring Boot 3 带来了许多新特性,包括对 Java 17 的支持、更好的性能优化以及对 G…

大疆上云API基于源码部署

文章目录 大疆上云API基于源码部署注意事项1、学习官网2、环境准备注意事项3、注册成为DJI开发者4、下载前后端运行所需要的包/依赖前端依赖下载后端所需要的Maven依赖包 用到的软件可以在这里下载5、MySQL数据库安装安装MySQL启动MySQL服务在IDEA中配置MySQL的连接信息 6、Red…

Js:正则表达式及正则表达式方法

① 创建正则表达式对象: /** 语法:* var reg new RegExp(正则表达式, 匹配模式);* 匹配模式(字符串类型):i --> 忽略大小写 g --> 全局匹配模式*/var reg new RegExp(a, i);var str abc; /** 正则表达式的方法&#…

【论文阅读】具身人工智能(Embodied AI)综述:连接数字与物理世界的桥梁

摘要 具身人工智能(Embodied AI)对于实现通用人工智能(AGI)至关重要,是连接数字世界与物理世界的各类应用的基础。近年来,多模态大模型(MLMs)和世界模型(WMs&#xff09…

数据结构--二叉树

目录 有序二叉树: 平衡二叉树: 234树: 红黑树 红黑树特点: 为什么红黑树是最优二叉树? 哈夫曼树和哈夫曼编码 有序二叉树: 平衡二叉树: 在有序二叉树的基础上得来的,且左右子…

【算法】图解两个链表相交的一系列问题

问: 给定两个可能有环也可能无环的单链表,头节点head1和head2。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null。如果两个链表长度之和为N,时间复杂度请达到O(N…

Python文件操作中编码解码问题

一、错误介绍 在学习python文件操作过程中遇到了UnicodeDecodeError错误,报错信息如下图所示。 二、错误产生的原因 下面是个人理解,可能存在错误,请理性看待。 windows默认按照GBK来进行编码的,而处理的文件是用UTF-8进行编码…

麦田物语学习笔记:构建游戏的时间系统

基本流程 1.代码思路 (1)新建一个TimeManager.cs (2)创建枚举变量来表示四季,在TimeManager里需要的变量有: 游戏内的秒,分钟,小时,天,月,年;游戏内的季节;控制一个季节有多少个月;控制时间的暂停;计时器tikTime (3)在Settings里添加计时器的阈值,以及各个时间的进位 (4)初始化…

《leetcode-runner》如何手搓一个debug调试器——指令系统

前文: 《leetcode-runner》如何手搓一个debug调试器——引言 《leetcode-runner》如何手搓一个debug调试器——架构 文章目录 什么是指令系统指令的组成部分leetcode-runner支持哪些指令如何解析用户输入的命令行指令识别流程 仓库地址:leetcode-runner …

Python 实现 NLP 的完整流程

💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…

学习ASP.NET Core的身份认证(基于JwtBearer的身份认证5)

用户在前端页面登录成功后会从服务端获取Token,后续调用服务器的服务接口时都得带着Token,否则就会验证失败。之前使用postman测试的时候,获取Token后再调用其它服务都是人工将Token添加到Header中,网页中没法这么做,只…

【深度学习实战】kaggle 自动驾驶的假场景分类

本次分享我在kaggle中参与竞赛的历程,这个版本是我的第一版,使用的是vgg。欢迎大家进行建议和交流。 概述 判断自动驾驶场景是真是假,训练神经网络或使用任何算法来分类驾驶场景的图像是真实的还是虚假的。 图像采用 RGB 格式并以 JPEG 格式…

下载文件,浏览器阻止不安全下载

背景: 在项目开发中,遇到需要下载文件的情况,文件类型可能是图片、excell表、pdf、zip等文件类型,但浏览器会阻止不安全的下载链接。 效果展示: 下载文件的两种方式: 一、根据接口的相对url,拼…

【漏洞分析】DDOS攻防分析

0x00 UDP攻击实例 2013年12月30日,网游界发生了一起“追杀”事件。事件的主角是PhantmL0rd(这名字一看就是个玩家)和黑客组织DERP Trolling。 PhantomL0rd,人称“鬼王”,本名James Varga,某专业游戏小组的…