代理模式实现

一、概念:代理模式属于结构型设计模式。客户端不能直接访问一个对象,可以通过代理的第三者来间接访问该对象,代理对象控制着对于原对象的访问,并允许在客户端访问对象的前后进行一些扩展和处理;这种设置模式称为代理模式;

2个点:

由代理对象去控制对原对象的访问(方法调用),客户端不直接对原对象进行访问,比如数据库的访问,不由Controller去控制;

在访问原对象时,可以有代理对象对原对象的功能(方法)进行扩展,比如访问数据库时,可以在代理对象里面进行开启事务和提交事务或回滚事务;

二、UML类图:

三、实现

1、静态代理实现

/*** Subject*/
public interface IUserMapperInterface {void save(String userName, String userNumber);
}

/*** RealSubject*/
public class UserMapperInterfaceImpl implements IUserMapperInterface {@Overridepublic void save(String userName, String userNumber) {System.out.println("执行insert语句,保存数据,并返回成功!");}
}

/*** 代理类*/
public class UserMapperInterfaceProxy implements IUserMapperInterface {private IUserMapperInterface userMapperInterface;public UserMapperInterfaceProxy(IUserMapperInterface userMapperInterface) {this.userMapperInterface = userMapperInterface;}@Overridepublic void save(String userName, String userNumber) {System.out.println("开启事务~~~");userMapperInterface.save(userName, userNumber);System.out.println("提交事务");}
}

/*** 客户端*/
public class Client {public static void main(String[] args) {String userName = "user name";String userNumber = "user number";UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());proxy.save(userName, userNumber);}
}

优缺点:

优点:可以在不修改目标类的前提下,对目标类进行扩展

缺点:

代码冗余,代理对象实现了和目标对象一致的接口,产生了一些冗余接口;

一旦目标接口中增加了新的方法,那么代理对象和真实接口实现都需要修改代码才行;

2、动态代理的实现:

动态代理与静态代理的区别:

静态代理在类加载完经已经加载JVM中,并且如有其他对象需要加载,需要修改代理对象;

动态代理只有在运行的时候才会去加载目标类, 当需要加载其他对象的时候,不需要修改,也就是动态代理可以代理任何对象Object;

动态代理有两种实现方式:JDK动态代理,和CGLib动态代理

  • JDK的动态代理,通过动态的生成一个接口对象的实现实例来实现对接口对象实例的功能扩展,在JDK的动态代理实现中,目标对象必须实现一个接口;
  • 通过反射包下的Proxy.newProxyInstance()方法实现

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 代理的工厂类*/
public class ProxyFactory {//需要代理的目标类private Object target;public ProxyFactory(Object target) {this.target = target;}public Object getTargetInstance() {//Proxy是反射包下(java.lang.reflect)的一个代理类,通过这个类的newProxyInstance(新建代理对象实例)来动态的加载一个代理目标对象,并返回//newProxyInstance方法需要传递三个参数,1、目标对象的类加载器, 2、目标对象实现的接口(如果有实现就有,没有实现就没有),3、目标对象需要执行的方法,相当于扩展静态代理中的那个save方法return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {//,目标对象被代理后需要执行的扩展方法,也有三个参数,1、目标对象,2、目标对象需要执行的方法实例,3、方法实例需要传递的参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开启一个事务~!");//执行方法,执行的时候把目标对象和方法参数传递过去method.invoke(target, args);System.out.println("提交事务");//返回值是指目标执行的方法的返回值,如果没有就返回null,在静态代理中,目标方法save的返回值是void,因此这里返回nullreturn null;}});}
}

/*** 客户端*/
public class Client {public static void main(String[] args) {String userName = "user name";String userNumber = "user number";//使用静态代理的模式实现代理,此时在类加载的时候就会创建该对象UserMapperInterfaceProxy proxy = new UserMapperInterfaceProxy(new UserMapperInterfaceImpl());proxy.save(userName, userNumber);System.out.println("静态代理实现的类名:" + proxy.getClass().getName());//使用动态代理的模式实现代理功能,在类加载的时候不会创建对象,在运行过程中才会去创建对象并调用对象 的方法ProxyFactory proxyFactory = new ProxyFactory(new UserMapperInterfaceImpl());IUserMapperInterface targetInstance = (IUserMapperInterface) proxyFactory.getTargetInstance();targetInstance.save(userName, userNumber);System.out.println("动态代理实现的类名:" + targetInstance.getClass().getName());}
}
  • CGLib动态代理的实现

CGLib是一个第三方的代码生成类库,运行时在内存中生成一个子类继承目标对象,从而实现对目标对象的扩展;SpringAOP和Hibernate都是基于CGLib动态代理实现的,而CGlib又是通过封装ASM工具包去操作字节码的;

引入包:如果是Spring项目,则不需要单独引入,SpringCore里面已经包含该包

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

目标类:


/*** CGLib方式实现代理的目标类*/
public class CGLibTargetClass {public void targetMethod(String userName, String userNumber) {System.out.println("CGLibTargetClass targetMethod");System.out.println("保存用户信息:username=" + userName + ",usernumber=" + userNumber);}
}

代理类:实现MethodInterceptor接口,并重写interceptor方法,

public class CGLibProxyIntercept implements MethodInterceptor {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("保存用户信息前开启事务");System.out.println(objects.toString());System.out.println(o.getClass().getName());methodProxy.invokeSuper(o, objects);System.out.println("保存用户信息后提交事务");return o;}
}

代理模式的总结:

由于CGlib采用的是继承目标类的方式去进行增强的,因此对于final类或方法是不能被继承的,无法使用CGlib的方式进行代理;

在jdk1.8后,实际上JDK动态代理比CGLib动态代理效率高,但JDK动态代理需要目标类实现一个接口,因此如果对象有实现接口,用JDK动态代理,没实现 用CGLib动态代理;

有缺点:

在客户端与目标对象之间起到中介作用,保护目标对象

对目标对象进行扩展,将客户端与目标对象分离,解耦

增加系统复杂度

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

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

相关文章

windows 搭建flutter环境,开发windows程序

环境安装配置&#xff1a; 下载flutter sdk https://docs.flutter.dev/get-started/install/windows 下载到本地后&#xff0c;随便找个地方解压&#xff0c;然后配置下系统环境变量 编译windows程序本地需要安装vs2019或更新的开发环境 主要就这2步安装后就可以了&#xff0…

Redis系列之底层数据结构字典Dict

Redis系列之底层数据结构字典Dict Dict数据结构 Dict是Redis数据结构中使用最为频繁的复合型数据结构&#xff0c;本质上是一个哈希表 查看redis6.0版本的源码&#xff0c;链接&#xff1a;https://github.com/redis/redis/blob/6.0/src/dict.h 哈希表的结构定义&#xff1…

【Azure 架构师学习笔记】- Azure Function (2) --实操1

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Function 】系列。 接上文【Azure 架构师学习笔记】- Azure Function (1) --环境搭建和背景介绍 前言 上一文介绍了环境搭建&#xff0c;接下来就在本地环境下使用一下。 环境准备 这里我下载了最新的VS studio&…

Vue3中ref和reactive的区别

在 Vue 3 中&#xff0c;ref 和 reactive 都是用于响应式编程的 API&#xff0c;但它们有不同的使用场景和行为。以下是它们之间的区别&#xff1a; 1. ref 用途&#xff1a;用于创建基本数据类型&#xff08;如字符串、数字、布尔值&#xff09;或对象的响应式引用。数据类型…

简明docker快速入门并实践方法

简明docker快速入门并实践方法 前言&#xff1a;1. 什么是Docker&#xff1f;2. Docker的基本概念3. 安装配置Docker4. Docker基本命令&#xff1a;5. 简单实践&#xff1a;拉取Nginx镜像-自定义配置-推送镜像步骤 1&#xff1a;拉取Nginx镜像步骤 1.5&#xff08;可选&#xf…

【NextJS】PostgreSQL 遇上 Prisma ORM

NextJS 数据库 之 遇上Prisma ORM 前言一、环境要求二、概念介绍1、Prisma Schema Language&#xff08;PSL&#xff09; 结构描述语言1.1 概念1.2 组成1.2.1 Data Source 数据源1.2.2 Generators 生成器1.2.3 Data Model Definition 数据模型定义字段(数据)类型和约束关系&…

左神算法基础提升--3

文章目录 Manacher 算法经典算法Manacher算法原理 单调栈或单调队列 Manacher 算法 经典算法 在每学习Manacher算法之前我们可能会使用一种比较经典暴力的算法&#xff1a;遍历str字符串&#xff0c;将字符串中的每个字符作为对称点&#xff0c;向两边扩散找到回文字段&#x…

【Docker】使用Dev Container进行开发

工作区 Dev Container 设置 新建一个文件夹 ./devcontainer 然后下面放 devcontainer.json 然后安装 vscode dev container 插件&#xff0c;然后 CtrlShiftP 启动 Container {"name": "PyTorch-Julia Development","image": "x66ccff/p…

浅谈操作系统与初识Linux

一、Linux操作系统的出现 1.1操作系统的出现以及相关的四个要素 1.2最早出现的操作系统及其创始人 起初&#xff0c;IBM为了让计算机可以以更低技术成本进行使用&#xff0c;以此来售卖计算机&#xff1b; 为计算机搭载上了Unix操作系统&#xff0c;Unix由肯汤普森用汇编语…

ElasticSearch下

DSL查询 叶子查询&#xff1a;在特定字段里查询特定值&#xff0c;属于简单查询&#xff0c;很少单独使用复合查询&#xff1a;以逻辑方式组合多个叶子查询或更改叶子查询的行为方式 在查询后还可以对查询结果做处理&#xff1a; 排序&#xff1a;按照1个或多个字段做排序分页…

牛客----mysql

查找除复旦大学的用户信息_牛客题霸_牛客网 题目&#xff1a;现在运营想要查看除复旦大学以外的所有用户明细包括的字段有 device_id、gender、age、university&#xff0c;请你取出相应数据 示例&#xff1a;user_profile iddevice_idgenderageuniversityprovince12138male…

Android SystemUI——CarSystemBar车载状态栏(九)

上一篇文章我们介绍了车载开发中的 CarSystemUI,而车载开发中的状态栏也被 CarSystemBar 所取代,这里我们就来看看一下车载系统中的状态栏——CarSystemBar。 一、车载状态栏创建 1、CarSystemBar 源码位置:/packages/apps/Car/SystemUI/src/com/android/systemui/car/sy…

java根据模板导出word,并在word中插入echarts相关统计图片以及表格

引入依赖创建word模板创建ftl模板文件保存的ftl可能会出现占位符分割的问题&#xff0c;需要处理将ftl文件中的图片的Base64删除&#xff0c;并使用占位符代替插入表格&#xff0c;并指定表格的位置在图片下方 Echarts转图片根据模板生成word文档DocUtil导出word文档 生成的wor…

链式前向星的写法

【图论02】动画说图的三种保存方式 降低理解门槛 邻接表 链式前向星 邻接矩阵_哔哩哔哩_bilibili 杭电ACM刘老师-算法入门培训-第12讲-拓扑排序及链式前向星_哔哩哔哩_bilibili 图论003链式前向星_哔哩哔哩_bilibili&#xff08;链式前向星的遍历&#xff09; head数组的下标…

Trie(算法版)

#include <iostream>using namespace std;const int N100010; int son[N][26],cnt[N],idx; //son记录trie数&#xff0c;cnt记录每个词出现的次数&#xff0c;idx记录每个字符所占⽤的下标//加入字符串 void add(char str[]){//idx 0既表⽰根节点也表⽰空节点int p 0;fo…

软件工程导论

第 1 章 软件工程学概述&#xff1a;介绍了软件危机的表现、产生原因及消除途径&#xff0c;阐述了软件工程的定义、基本原理和方法学&#xff0c;还讲解了软件生命周期和软件过程的相关概念&#xff0c;包括瀑布模型、快速原型模型等多种软件开发模型当当。第 2-8 章 软件生命…

想品客老师的第一天:值类型使用

前面两章的摘要 ECMAscript&#xff08;也就是ES&#xff09;是JavaScript的一个标准&#xff0c;就像c的c11和c99一样&#xff0c;几把的一年出一套标准 freeze()是一个对象方法&#xff0c;表示锁定、固定一个对象不可改变&#xff08;因为const对于标量不可变&#xff0c;…

容器渗透横向

本质上要获得 1.获得容器IP段 2.获得主机IP段 3.获得本机IP 4.通过CNI或Docker0等扫描本机端口 Flannel 容器信息 rootubuntu-linux-22-04-desktop:/home/parallels/Desktop# k get po -A -o wide NAMESPACE NAME …

贪心算法(题1)区间选点

输出 2 #include <iostream> #include<algorithm>using namespace std;const int N 100010 ;int n; struct Range {int l,r;bool operator <(const Range &W)const{return r<W.r;} }range[N];int main() {scanf("%d",&n);for(int i0;i&l…

解决本地运行MR程序访问权限问题

文章目录 1. 提出问题2. 解决问题2.1 临时解决方案2.2 永久解决方案 3. 小结 1. 提出问题 运行DeduplicateIPsDriver类&#xff0c;抛出如下异常&#xff1a; 该错误信息表明在尝试运行 DeduplicateIPsDriver 类时&#xff0c;遇到了 HDFS&#xff08;Hadoop 分布式文件系统&a…