Java设计模式-结构型模式-代理模式

代理模式

  • 代理模式
    • 静态代理
    • 动态代理
      • JDK动态代理
      • CGlib动态代理

代理模式

创建一个代理对象来控制对原始对象的访问,可以用来扩展原始对象的功能,同时保护原始对象
一般使用代理模式的目的有两个:

  1. 保护目标对象
  2. 增强目标对象

代理模式有两种实现方案:静态代理 和 动态代理
在这里插入图片描述
下面以Dao层执行sql语句为例,讲述代理模式的 应用

静态代理

静态代理就是通过组合/继承的方式,代理类关联原始类,通过调用代理类的方法来实现 原始类的方法增强
这里有一个UserDaoImpl,作为原始类,提供一个模拟插入用户的接口

public interface UserDao {void insert();
}
/*****************************************************/public class UserDaoImpl implements UserDao{public void insert(){System.out.println("插入一个用户");}
}

创建一个静态代理类,StaticProxyUserDao,完成对userDao的增强

public class StaticProxyUserDao implements UserDao{private UserDao userDao;public StaticProxyUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void insert(){//事务开启...System.out.println("事务开启");userDao.insert();//方法增强...//事务提交...System.out.println("事务提交");}
}

测试代码如下,很容易理解,就不解释了

@Test
public void staticProxyTest(){//直接使用UserDao userDao = new UserDaoImpl();userDao.insert();System.out.println("---------------------------------------------------");//通过静态代理的方式,增强insert()方法StaticProxyUserDao staticProxyUserDao = new StaticProxyUserDao(userDao);staticProxyUserDao.insert();
}输出:
插入一个用户
---------------------------------------------------
事务开启
插入一个用户
事务提交

动态代理

通过静态代理的方式可以实现方法的增强,但对于每个增强的类,都需要再写一个代理类,这样显得代码比较臃肿,所以就有了动态代理,可以在程序执行过程中,动态的代理目标类。

动态代理有两种实现方式:JDK动态代理CGlib动态代理

JDK动态代理

JDK动态代理是Java标准库中提供的一种代理方式
JDK动态代理是依赖接口的。
实现方式:通过Proxy类中的 静态方法 newProxyInstance(…)实现

@Test
public void JdkProxyTest(){UserDao userDao = new UserDaoImpl();/** 参数1:指定一个类加载器* 参数2:指定接口 getInterfaces()* 参数3:指定对应的代理方法* */System.out.println();UserDao proxyUserDao = (UserDao)Proxy.newProxyInstance(UserDao.class.getClassLoader(), UserDaoImpl.class.getInterfaces(), (proxy, method, args) -> {System.out.println("事务开启");Object invoke = method.invoke(userDao,args);System.out.println("事务关闭");return invoke;});proxyUserDao.insert();
}

可以看出来,JDK动态代理的方法 必须在接口中有定义,所以,如果想要代理没有在接口中定义的方法,这就需要使用CGlib来实现

CGlib动态代理

CGlib 是基于 类继承实现的,通过继承目标类 来实现类的代理,所以目标类必须是可继承的
CGlib支持更细粒度的代理——针对某个方法进行代理
CGLIB是第三方提供的包,需要引入Jar包

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.1</version>
</dependency>

spring-core jar包里包含cglib ,所以使用spring框架的工程可以直接使用。
实现方式:通过Enhancer类实现,如下:

@Test
public void CGlibProxyTest(){// 创建Enhancer对象 类似于 Proxy类Enhancer enhancer = new Enhancer();// 设置父类的字节码对象 即需要代理的类enhancer.setSuperclass(UserDaoImpl.class);//设置回调函数,增强方法/*** o 代理对象,即生成的代理类的实例,这里是生成的代理对象,不是被代理对象* method 被代理方法的Method对象* args 方法调用时传递的参数数组* methodProxy 方法代理对象*/enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {System.out.println("事务开启");//这里注意使用的是 invokeSuper() 调用的是父类的接口Object invoke = methodProxy.invokeSuper(o,objects);System.out.println("事务关闭");return invoke;});// 生成代理对象UserDaoImpl proxy = (UserDaoImpl) enhancer.create();proxy.insert();
}

这里提一下注意的点:

JDK动态代理,依赖接口完成代理,没有实例对象,所以需要传入实例对象,
即 method.invoke(userDao,args); 中的userDao,所以在代理之前,需要先有个实例化的对象

而CGlib动态代理,依赖类继承实现,本身是知道代理对象的所有结构的,所以不需要传入实例对象,所以:
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
System.out.println(“事务开启”);
Object invoke = methodProxy.invokeSuper(o,objects);
System.out.println(“事务关闭”);
return invoke;
});
第一个参数是 代理对象,而不是被代理对象,调用方法使用的是 invokeSuper() 不是invoke(),调用的是父类的接口

关于CGlib和JDK代理的详细代理过程,可以看下这篇文章
https://blog.csdn.net/ren9436/article/details/125602288

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

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

相关文章

原型链污染攻击

想要很清楚了理解原型链污染我们首先必须要弄清楚原型链这个概念 可以看这篇文章&#xff1a;对象的继承和原型链 目录 prototype和__proto__分别是什么&#xff1f; 原型链继承 原型链污染是什么 哪些情况下原型链会被污染&#xff1f; 例题1&#xff1a;Code-Breaking 2…

浅析网络协议-HTTP协议

1.HTTP简介 HTTP协议是Hyper Text Transfer Protocol&#xff08;超文本传输协议&#xff09;的缩写,是用于从万维网&#xff08;WWW:World Wide Web &#xff09;服务器传输超文本到本地浏览器的传送协议。 HTTP是一个基于TCP/IP通信协议来传递数据&#xff08;HTML 文件, 图…

​ArcGIS Pro怎么生成山顶点

山顶点是指山脉、山丘或山脉系统中最高的地点&#xff0c;通常是山的最高峰&#xff0c;这是山地地貌中的最高点&#xff0c;往往是山脉的标志性特征之一&#xff0c;这里为大家介绍一下如何使用ArcGIS Pro获取山顶点&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用…

​​​​​​​​​​​​​​汽车网络信息安全分析方法论

目录 1.典型信息安全分析方法 1.1 HEAVENS威胁分析模型 1.2 OCTAVE威胁分析方法 1.3 Attack Trees分析方法 2. 功能安全与信息安全的关系讨论 与Safety的典型分析方法一样&#xff0c;Security也有一些典型的信息安全威胁分析方法(TARA分析)&#xff0c;根据SAE J3061、I…

整治PPOCRLabel中cv2文件读取问题(更新中)

PPOCRLabel 使用PPOCRLabel对ocr预标注结果进行纠正由于PaddleOCR代码库十分混乱,路径经常乱调pip和代码库的代码&#xff08;pip库和源码冲突&#xff09;,经常报错&#xff0c;因此paddleocr和ppocrlabel都是使用pip包;PPOCRLabel中使用了cv2进行图片数据的读取&#xff0c;…

基于springboot+vue的学生毕业离校信息网站

项目介绍 该学生毕业离校系统包括管理员、学生和教师。其主要功能包括管理员&#xff1a;首页、个人中心、学生管理、教师管理、离校信息管理、费用结算管理、论文审核管理、管理员管理、留言板管理、系统管理等&#xff0c;前台首页&#xff1b;首页、离校信息、网站公告、留…

【C语言 | 预处理】C语言预处理详解(一) —— #define、#under、#if、#else、#elif、#endif、#include、#error

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

不同优化器的应用

简单用用&#xff0c;优化器具体参考 深度学习中的优化器原理(SGD,SGDMomentum,Adagrad,RMSProp,Adam)_哔哩哔哩_bilibili 收藏版&#xff5c;史上最全机器学习优化器Optimizer汇总 - 知乎 (zhihu.com) import numpy as np import matplotlib.pyplot as plt import torch # …

矩阵起源加入 OpenCloudOS 操作系统开源社区,完成技术兼容互认证

近日&#xff0c;超融合异构云原生数据库 MatrixOne企业版软件 V1.0 完成了与 OpenCloudOS 的相互兼容认证&#xff0c;测试期间&#xff0c;整体运行稳定&#xff0c;在功能、性能及兼容性方面表现良好。 一、产品简介 矩阵起源 MatrixOrigin 致力于建设开放的技术开源社区和…

pychon/PIL/opencv/json学习过程中遇到的问题

1. 使用PIL.Image读取图片 注意&#xff1a;pytorch中对图像预处理是transforms的输入必须是PIL格式的文件&#xff0c;使用cv2读取的图片就按照第二条的代码处理&#xff08;3通道合并、归一化处理&#xff09; from PIL import Image img Image.open("test1.jpg"…

tensorboard报错解决:No dashboards are active for the current data set

版本&#xff1a;tensorboard 2.10.0 问题&#xff1a;文件夹下明明有events文件&#xff0c;但用tensorboard命令却无法显示。 例如&#xff1a; 原因&#xff1a;有可能是文件路径太长了&#xff0c;导致系统无法读取文件。在win系统中规定&#xff0c;目录的绝对路径不得超…

vue,react虚拟dom

Virtual DOM 前言 在传统的Web开发中&#xff0c;直接操作真实的DOM通常是一个昂贵且低效的操作。为了解决这个问题&#xff0c;Virtual DOM&#xff08;虚拟DOM&#xff09;被引入为一个中间层&#xff0c;允许开发者在内存中进行操作&#xff0c;从而避免频繁且不必要的真实D…