代理模式实现

devtools/2025/1/19 0:43:23/

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

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.ppmy.cn/devtools/151704.html

相关文章

SK海力士(SK Hynix)是全球领先的半导体制造商之一,其在无锡的工厂主要生产DRAM和NAND闪存等存储器产品。

SK海力士&#xff08;SK Hynix&#xff09;是全球领先的半导体制造商之一&#xff0c;其在无锡的工厂主要生产DRAM和NAND闪存等存储器产品。以下是SK海力士的一些主要产品型号和类别&#xff1a; DRAM 产品 DDR4 DRAM 特点: 高速、低功耗&#xff0c;广泛应用于PC、服务器和移…

选择saas 还是源码主要考虑

公司业务规模&#xff1a;小型企业可能会发现SaaS提供的即用型解决方案更符合其需求&#xff0c;而大型企业可能需要源码以实现更高的定制性和控制权。 公司技术专长&#xff1a;缺乏技术团队的企业可能会倾向于使用SaaS&#xff0c;而那些拥有强大IT部门的企业可能更适合管理…

【优选算法】三数之和(双指针算法)

必须有为成功付出代价的决心&#xff0c;然后想办法付出这个代价。 目录 一、【题目&#xff1a;15. 三数之和 - 力扣&#xff08;LeetCode&#xff09;】 二、【代码原理】 三、【代码】 一、【题目&#xff1a;15. 三数之和 - 力扣&#xff08;LeetCode&#xff09;】 需…

LLM实现视频切片合成 前沿知识调研

1.相关产品 产品链接腾讯智影https://zenvideo.qq.com/可灵https://klingai.kuaishou.com/即梦https://jimeng.jianying.com/ai-tool/home/Runwayhttps://aitools.dedao.cn/ai/runwayml-com/Descripthttps://www.descript.com/?utm_sourceai-bot.cn/Opus Cliphttps://www.opu…

VSCode 的部署

一、VSCode部署 (1)、简介 vsCode 全称 Visual Studio Code&#xff0c;是微软出的一款轻量级代码编辑器&#xff0c;免费、开源而且功能强大。它支持几乎所有主流的程序语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比Diff、版本管理GIT等特性&…

C# 声明废弃特性

C# 声明废弃 使用特性[Obsolete] 可以在类&#xff0c;或者方法上方使用 类 如果调用该类&#xff0c;将显示 方法 基本用法 如果使用&#xff0c;将显示 高级用法 public ObsoleteAttribute(string message, bool error); //string message 提示可以拿什么来替换该语句 …

C#Halcon视觉流程框架个人封装流程心得

一&#xff0c;实现效果 1&#xff0c;初始界面 2&#xff0c;加载流程 3&#xff0c;点击流程列表“加载2D图像" 4&#xff0c;设置图像预处理参数与画线找线 5&#xff0c;执行流程 6&#xff0c;折叠工具箱 7&#xff0c;折叠操作区域 二&#xff0c;实现流程 1&…

【17】Word:林楚楠-供应链❗

目录 题目 NO1.2 NO3 NO4 NO5 NO6 NO7 NO89 题目 NO1.2 另存为&#xff1a;文件→另存为→文档→文件名/考生文件夹F12/FnF12→文件名/考生文件夹 插入→分节符→文本框→输入文件→排版_居中对齐→间距/回车去掉文本框的边框→选中文本框→格式&#xff1a;形状轮廓…