设计模式之代理模式

写在前面

1:介绍

1.1:什么时候使用代理模式

当我们有对象因为安全性,不能直接对外暴露,或者是需要对对象的操作本身记录日志等信息时就可以考虑使用代理模式,

1.2:UML类图

享元设计模式,包含如下元素:

1:被代理类需要被代理的类
2:代理类代理类
3:客户端类使用代理类执行操作的类

UML图如下:

另外,代理又分为静态代理和动态代理,静态代理就是在编译器已经确定的代理方式,即是硬编码到程序中的,这种方式不灵活,动态代理是在运行期动态确定的代理方式,灵活度高。动态代理主要有jdk动态代理(需要有接口),asm,cglib(基于asm,简化操作)。来看下。

2:实例

源码 。

2.1:场景

数据库操作场景,需要在service方法调用前开启事务,方法调用后提交事务。

2.2:静态代理

  • 定义PersonService接口
public interface PersonService {public void savePerson();
}
  • 定义PersonServiceImpl
public class PersonServiceImpl implements PersonService {@Overridepublic void savePerson() {System.out.println("保存人了");}
}
  • 定义事务类
public class Transaction {public void beginTransaction(){System.out.println("开启事务 ");}public void commit(){System.out.println("提交事务");}
}
  • 定义代理类
public class PersonServiceProxy implements PersonService {//目标类private PersonService personService;//增强类private Transaction transaction;//利用构造函数将目标类和增强类注入public PersonServiceProxy(PersonService personService,Transaction transaction) {this.personService = personService;this.transaction = transaction;}@Overridepublic void savePerson() {// 这是每个类都需要的操作transaction.beginTransaction();personService.savePerson();// 这是每个类都需要的操作transaction.commit();}
}
  • 测试
@Test
public void serviceStatic() {new PersonServiceProxy(new PersonServiceImpl(), new Transaction()).savePerson();
}开启事务 
保存人了
提交事务

假定我们现在又有个AnimalService如下:

public interface AnimalService {public void saveAnimal();
}public class AnimalServiceImpl implements AnimalService {@Overridepublic void saveAnimal() {System.out.println("保存动物了");}
}

则需要重新定义一个AnimalService的代理类来为其添加事务,如下:

public class AnimalServiceProxy implements AnimalService {//目标类private AnimalService animalService;//增强类private Transaction transaction;//利用构造函数将目标类和增强类注入public AnimalServiceProxy(AnimalService animalService, Transaction transaction) {this.animalService = animalService;this.transaction = transaction;}@Overridepublic void saveAnimal() {// 这是每个类都需要的操作(PersonService写过一遍了,这里又要再写一遍,好痛苦!!!)transaction.beginTransaction();animalService.saveAnimal();// 这是每个类都需要的操作(PersonService写过一遍了,这里又要再写一遍,好痛苦!!!)transaction.commit();}
}

测试:

new AnimalServiceProxy(new AnimalServiceImpl(), new Transaction()).saveAnimal();开启事务 
保存动物了
提交事务

如果我们有100个service,则同样的定义对应代理类的工作就要做100次,岂不疯了!!!但是,幸好我们有动态代理,接下来看下使用动态代理解决这个需要重复定义代理类的问题。

2.2:jdk动态代理

  • 定义InvocationHandler
public class ServiceInvocationHandler implements InvocationHandler {// 被代理的对象private Object target;private Transaction transaction;public ServiceInvocationHandler(Object obj){this.target=obj;this.transaction = new Transaction();}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 使用静态代理重复的事务开启操作就移动到这里了(只需要定义一次)this.transaction.beginTransaction();method.invoke(this.target, args);// 使用静态代理重复的事务提交操作就移动到这里了(只需要定义一次)this.transaction.commit();return null;}
}
  • 测试代理PersonService
@Test
public void serviceJdkProxy() {((PersonService) ServiceProxyFactory.makeProxy(new PersonServiceImpl())).savePerson();
}开启事务 
保存人了
提交事务

如果是增加了AnimalService只需要增加如下代码即可获取代理类:

((AnimalService) ServiceProxyFactory.makeProxy(new AnimalServiceImpl())).saveAnimal();开启事务 
保存动物了
提交事务

但是,jdk动态代理有一个缺点就是必须要有接口,这在一定程度上限制了灵活度,如果是我们么有接口的话,则可以考虑使用cjlib来生成动态代理,一起看下!

2.3:cglib动态代理

  • 定义MethodInterceptor子类
public class ServiceMethodInterceptor implements MethodInterceptor {private Transaction transaction = new Transaction();@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {// 开启事务(只需要写一次)transaction.beginTransaction();methodProxy.invokeSuper(o, objects);// 提交事务(只需要写一次)transaction.commit();return null;}
}
  • 获取代理工厂类
public class CjlibProxyFactory {public static Object getGcLibDynProxy(Object target){Enhancer enhancer=new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(new ServiceMethodInterceptor());Object targetProxy= enhancer.create();return targetProxy;}
}
  • 测试
@Test
public void serviceCjlibProxy() {((PersonServiceImpl) CjlibProxyFactory.getGcLibDynProxy(new PersonServiceImpl())).savePerson();
}开启事务 
保存人了
提交事务

如果是增加了AnimalService则增加如下代码即可获取代理类:

((AnimalServiceImpl) CjlibProxyFactory.getGcLibDynProxy(new AnimalServiceImpl())).saveAnimal();开启事务 
保存动物了
提交事务

写在后面

参考文章列表

java都有哪些动态代理机制? 。

Java中的代理模式——静态代理以及分析静态代理的缺点 。

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

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

相关文章

五十、Spring

1.Spring概述 1.1 Spring是什么 Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架。 提供了表现层 SpringMVC和持久层 Spring JDBC Template以及 业务层 事务管理等众多的企业级应用 技术,还能整合开源世界众多著名的第三方框架和类库&#xf…

4个顶级WooCommerce商城多站点库存同步WordPress插件

经营几家网上商店是令人兴奋的。但是,这也是一项艰巨的工作,尤其是当您意识到需要同步这些商店的库存时。好消息是,有 WooCommerce 多站点库存同步插件和选项可以加快速度。 WooCommerce 多站点网络可让您将所有在线商店无缝地安置在一个屋檐…

【Tauri + React 实战】VCluster - 了解技术选型与开发环境配置

VCluster A React Tauri App as visualizer of apps cluster on windows. 背景介绍 VCluster是一个在开发环境下,用以对一系列应用集群(如分布式、微服务)进行可视化管理的桌面应用程序,目标是实现类似 docker-compose 那样的集…

TabBar和TabBarView实现顶部滑动导航

home.dart子页面主要代码&#xff1a; import package:flutter/material.dart;class HomePage extends StatefulWidget {const HomePage({super.key});overrideState<HomePage> createState() > _HomePageState(); }class _HomePageState extends State<HomePage&…

windows环境hadoop报错‘D:\Program‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

Hadoop版本为2.7.3&#xff0c;在环境配置好后&#xff0c;检查hadoop安装版本&#xff0c;报如标题所示错误&#xff0c;尝试网上主流的几种方法均无效。 错误&#xff1a;windows环境hadoop报错’D:\Program’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误方…

TCP/IP网络编程 第十一章:进程间通信

进程间通信的基本概念 在上一章中我们讲到&#xff0c;进程自身有独立的内存空间&#xff0c;进程之间是相互独立的存在。因此在没有任何机制的支持下&#xff0c;我们可以将进程看作相互孤立的存在。 但是进程之间在某种程度上也是要“交流”的&#xff0c;下面正式介绍进程…

在uni中使用vue3写h5的pdf导出

先安装依赖 npm install --save html2canvas npm install jspdf --save 把dom转canvas&#xff0c;屏幕截图基于 DOM&#xff0c;因此可能不是 100% 准确到真实表示&#xff0c;因为它不会制作实际的屏幕截图&#xff0c;而是根据页面上可用的信息构建屏幕截图。 components…

linux 一键安装docker docker-compose

# 环境 deploy.sh docker-19.03.9.tgz docker-compose-linux-x86_64 tar -zxvf docker-19.03.9.tgz mv docker-19.03.9 docker cp docker/* /usr/bin/ touch /etc/systemd/system/docker.service cat << EOG > /etc/systemd/system/docker.service [Unit] Descripti…

【技巧】Maven重复依赖分析查找

【技巧】Maven重复依赖分析查找 遇到奇葩的错误可以考虑是不是依赖冲突了 比如同一段代码 再这个项目中好好的 另一个项目中不能用等 idea安装插件 maven helper 打开pom文件 输入要查找的依赖 将不用的排除掉 右键排除即可

“深入解析API接口:原理、用途和最佳实践“

API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;是不同软件或系统之间进行交互的桥梁&#xff0c;它提供了一组定义好的规则和功能&#xff0c;使得不同的应用程序能够相互通信和交换数据。API接口的理解、应用和最佳实践对于开发者…

在阿里云平台注册一个域名

我们访问阿里云官网 阿里云 然后 我们右上角点击登录 然后 按正常操作流程登录 登录成功后 我们点击控制台 我们将鼠标 移入 右上角 图片指向的位置 我们点击域名 进入界面后点击注册域名 在输入框中输入域名内容 然后 按回车 然后弹出的列表 我们可以选一个未注册的 点击…

解决Linux打开文件数过多error:too many open files

解决Linux打开文件数过多error:too many open files #查看当前的最大打开文件数 ulimit -n #默认只有1024,当负载较大的服务器时&#xff0c;很容易遇到error: too many open files。因此&#xff0c;需要将其改大。#可临时修改&#xff0c;但重启后就无效 ulimit -n 65535 #查…

Druid-排查conditionDoubleConstAllow配置问题(double const condition)

Druid-排查conditionDoubleConstAllow配置问题(double const condition) 报错信息 Caused by: java.sql.SQLException: sql injection violation, dbType postgresql, druid-version 1.2.18, double const condition : SELECT * FROM test where 11 AND TRUE AND TRUE关键词&…

正则表达式概念以及语法的使用

目录 1.概念 2. 为什么使用正则表达式&#xff1f; 3. 语法 1.普通字符 非打印字符 2. 特殊字符 3. 限定符 4. 定位符 5. 运算优先级 3.匹配规则 1. 基本模式匹配 2. 字符簇 3. 确定重复出现 1.概念 正则表达式(Regular Expression)是一种文本模式&#xff0c;包…

【Docker】docker-compose基本使用

【Docker】docker-compose基本使用 文章目录 【Docker】docker-compose基本使用1. docker 项目部署弊端2. docker-compose 简介3. 实践4. 模板命令4.1 build 指令4.2 command 指令4.3 container_name 指令4.4 depends_on 指令4.5 env_file 指令4.6 environment 指令4.7 image 指…

基于Redisson的Redis分布式锁

Redisson分布式锁_redissonclient_甩锅虾的博客-CSDN博客 *** 分布式锁*/ public interface DistributedLock {/*** 尝试获取锁* param lockName* param seconds* return*/Boolean tryAcquire(String lockName, long seconds, TimeUnit unit);/*** 释放锁* param lockKey*/v…

如何使用自动化构造随机路由模型

为什么要仿真随机路由&#xff1f; 路由器测试中&#xff0c;为了最大程度还原现网路由情况&#xff0c;评估路由器在现网环境下稳定工作各项指标&#xff0c;需要对导入路由进行离散仿真&#xff0c;目前路由仿真可分为导入路由与生成路由两种方式&#xff0c;导入路由需要现…

vue如何使用webscorket实现多人协同在线表格填写

要使用WebSocket在Vue中实现多人协同在线表格填写&#xff0c;你可以按照以下步骤进行操作&#xff1a;1. 安装WebSocket库&#xff1a;首先&#xff0c;在Vue项目中安装WebSocket库。你可以使用 socket.io-client 库来处理WebSocket通信。使用npm或yarn安装它&#xff1a;npm …

学习遇上的一点补救

从开始学习java到现在逐步确定好发展路线。是时候停一下步伐了。 之前不停的往前走&#xff0c;从学校的课程、书本开始&#xff0c;没有借助网课、视频&#xff0c;依靠自己一步一个脚印。从Java实用程序、Javaweb、JavaEE然后选择MySQL数据库、然后觉得有必要对前端了解&…

think-on-graph: 基于知识图谱的大模型推理

概述 本文的研究背景是大规模语言模型在复杂推理任务中存在困难并展示了较低的性能&#xff0c;特别是在需要知识的追溯能力、及时性和准确性的场景中。 过去的方法主要面临两个问题&#xff1a;推理不负责任容易生成虚构或带有有害文本&#xff0c;以及模型在预训练阶段无法…