代理 模式

article/2025/10/2 6:19:40

代理模式

Proxy Pattern

为其他对象提供一个代理以控制对这个对象的访问

可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。

静态代理

直接写死的代码的代理逻辑

在这里插入图片描述

动态代理

动态的生成代理类。有JDK动态代理,CGLIB代理

在这里插入图片描述

JDK自带的动态代理 :

  • java.lang.reflect.Proxy , 作用:动态生成代理类和对象
  • java.lang.reflect.InvocationHandler(处理器接口) , 可以通过invoke方法实现对真实角色的代理访问。每次通过Proxy生成代理类对象时都要指定对应的处理器对象

动态代理相比于静态代理的优点
抽象角色中(接口)声明的所以方法都被转移到调用处理器一个集中的方
法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

应用场景:

  • 安全代理:屏蔽对真实角色的直接访问。
  • 远程代理:通过代理类处理远程方法调用(RMI)。
  • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。( 比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。)

开发框架中应用场景:

实际上,随便选择一个技术框架都会用到代理模式!

struts2中拦截器的实现;
数据库连接池关闭处理;
Hibernate中延时加载的实现;
AspectJ的实现 , spring中AOP的实现;
mybatis中实现拦截器插件;
日志拦截;
声明式事务处理;
web service;
RMI远程方法调用

核心角色:

  1. 抽象角色:定义代理角色和真实角色的公共对外方法;
  2. 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用,– 关注真正的业务逻辑!;
  3. 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 将统一的流程控制放到代理角色中处理!

静态代理

需要定义接口或父类,被代理对象和代理对象一起实现相同的接口或继承相同的父类

定义接口:IUserDao.java

public interface IUserDao {void save();
}

定义目标对象

package com.ung.designMode.proxy;/*** @author: wenyi* @create: 2022/9/19* @Description:*/
public class UserDao implements IUserDao {@Overridepublic void save() {System.out.println("。。。。保存好了数据。。。。");}
}

定义代理对象,都实现相同的接口

可以在调用目标方法前后来进行代理操作,什么开启事务,提交事务等

package com.ung.designMode.proxy;/*** @author: wenyi* @create: 2022/9/19* @Description:*/
public class UserDaoProxy implements IUserDao {private IUserDao iUserDao;public UserDaoProxy(IUserDao iUserDao) {this.iUserDao = iUserDao;}@Overridepublic void save() {//在这里可以定义调用前的执行操作System.out.println("调用前的操作代理");iUserDao.save();//在这里可以定义调用后的执行操作System.out.println("调用后的操作代理");}
}

测试

package com.ung.designMode.proxy;import org.junit.Test;import static org.junit.Assert.*;public class UserDaoTest {@Testpublic void save() {//目标对象UserDao userDao = new UserDao();//代理对象,将目标对象传给代理对象,建立代理关系UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);//执行的也是代理的方法userDaoProxy.save();}
}

在这里插入图片描述

这样的代理,可以实现不修改目标对象的功能,来进行功能的扩展增强;

但是这样有缺陷,都需要实现相同的接口,导致代理类很多,

如果接口的方法修改,呐需要变动的就很多,不易维护

可以使用动态代理,也叫 JDK代理,接口代理

JDK动态代理
  1. 代理对象可以不用实现接口

  2. 利用jdk的api来生成代理对象,动态的在内存中构建代理对象

    需要我们指定一个创建代理对象和目标对象实现的接口

在这里插入图片描述

总结:代理对象可以不用实现接口,但是目标对象要实现接口,否则不能使用动态代理

对之前的案例,相同的基础上,新建一个ProxyFactory的代理工厂类,在测试类中建立目标对象和代理对象的联系,最后调用代理对象的方法就可以

新建 ProxyFactory 代理类

package com.ung.designMode.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author: wenyi* @create: 2022/9/19* @Description: 代理类工厂*/
public class ProxyFactory {//    维护一个目标对象private Object target;public ProxyFactory(Object target) {this.target = target;}public Object getProxyInstance() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),//类加载器target.getClass().getInterfaces(),//目标类实现的接口new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("调用前的开启事务");Object returnValue = method.invoke(target, args);System.out.println("调用后的提交事务");return returnValue;}});}
}

测试

package com.ung.designMode.proxy;import org.junit.Test;import static org.junit.Assert.*;public class UserDaoTest {@Testpublic void save() {//目标对象UserDao userDao = new UserDao();
//        //代理对象,将目标对象传给代理对象,建立代理关系
//        UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
//        //执行的也是代理的方法
//        userDaoProxy.save();System.out.println("原始的目标对象"+userDao.getClass());//代理对象IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance();System.out.println("代理对象"+proxy.getClass());proxy.save();}
}

在这里插入图片描述

idea中通过配置VM参数可以将动态生成的代理类的字节码文件保存到本地,方便观察分析代理类的结构。

JDK8及以前版本:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
JDK8以后版本:-Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true

在这里插入图片描述

可以看到由JDK代理实现的代理类 是通过实现接口,继承Proxy的单继承,默认继承了Proxy就不可以再继承其他类了

实现被代理类实现的接口方法,如果被代理的目标类有私有方法,那这样生成的代理类就不能对私有方法进行代理

CGLIB 动态代理

对类进行代理,code generator library 代码生成库,动态生成字节码对象;

创建代理拦截器

package com.ung.designMode.proxy;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @author: wenyi* @create: 2022/9/19* @Description:*/
public class LycCglibProxyInterceptor implements MethodInterceptor {// proxy:代理对象 method:目标对象中的方法 args:目标对象中的方法 methodProxy:代理对象中的代理方法对象@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("执行前");Object rtnObj = methodProxy.invokeSuper(o, objects);System.out.println("执行后");return rtnObj;}
}

测试

package com.ung.designMode.proxy;import org.junit.Test;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;public class LycCglibProxyInterceptorTest {@Testpublic void intercept() {//创建空的字节码对象Enhancer enhancer = new Enhancer();//设置字节码对象的父类就是目标类enhancer.setSuperclass(UserDao.class);//回调对象Callback callback =new LycCglibProxyInterceptor();//设置字节码对象的回调enhancer.setCallback(callback);//代理对象UserDao userDaoProxy = (UserDao) enhancer.create();//调用方法userDaoProxy.save();}
}

可以看到也成功代理

//保存生成的字节码文件
byte[] generate = enhancer.getStrategy().generate(enhancer);
FileOutputStream fileOutputStream = new FileOutputStream(
new File("C:\\个人文档\\learing\\lyccglibtest.class"));
fileOutputStream.write(generate);
fileOutputStream.flush();
fileOutputStream.close();

在这里插入图片描述

(queryCost 是被代理的方法)

可以看到 通过CGLIB动态代理生成的 代理类,是创建一个新的类继承被代理类,在重写了父类的方法,

在重写的方法里面调用的接口的intercept方法,就是queryCost 被代理的方法,在这里可以进行目标方法的增强;

这样通过子类重写父类的方式的代理,要求被代理的方法不能是final方法修改,否则子类无法重写进行代理;

总结:

  1. 如果目标对象实现了接口,默认会使用JDK的动态代理实现AOP

    底层依赖 java 反射实现增强,生成一个实现代理接口的代理类

    只能代理实现接口的目标类,代理类和目标类都要实现相同的接口

  2. 如果目标对象没有实现接口,那就必须用CGLIB动态代理

    通过生成一个目标类的子类,来重写目标方法实现代理增强,有拦截器拦截父类的方法调用,目标类不能用final修改方法和类,否则不能继承和重写方法;

Spring会再两者之间转换


http://chatgpt.dhexx.cn/article/kdh46kPa.shtml

相关文章

代理模式例子

1.概念 代理模式就是为某个对象提供一种代理,以控制对这个对象的访问。 2.涉及角色 抽象角色:声明真实对象和代理对象的共同接口; 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象&#xff…

代理模式的使用

一.代理模式 代理模式是java常用的设计模式。 代理的定义:为其他对象提供一种代理以控制对这个对象的访问。 简单点说就是代理对象与实际对象都实现了相同的接口,我们可以通过代理对象来间接的访问实际对象,也因为这种间接性,我…

C++之代理模式

目录 模式思想 简介 组成 优点 代码实现 情景 如果不使用代理的话: 加代理的话: 结果 模式思想 简介 代理模式: 通过代理类,来控制实际对象的访问权限。 在某些情况下,一个对象不适合或者不能直接引用另…

代理模式与动态代理模式

原文地址:点击打开链接 1、代理模式 所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。 代理模…

设计模式之代理模式(C++)

作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、代理模式是什么? 代理模式是一种结构型的软件设计模式,在不改变原代码前提下,提供一个代理…

动态代理模式详解

目录 (一)什么是动态代理模式 (二)动态代理模式入门案例 1.完成一个账户转账的功能 2. v1.0版本为转账添加一个事务 3.v2.0将事务从业务层和从持久层剥离 4.v3.0将事务使用动态代理完成 5.v3.0通过cglib实现代理模式 &…

三种代理模式详解

文章目录 二、代理模式(Proxy Pattern)1、常见的几种代理模式:2、静态代理3、JDK动态代理4、CGLib代理5、CGLib和JDK动态代理的区别 二、代理模式(Proxy Pattern) 根据B站狂神视频整理:https://www.bilibil…

Spring的代理模式

1、代理模式 为什么要学习代理模式? 因为这就是springAOP的底层!【springAOP和springMVC】 代理模式的分类: 静态代理动态代理 1.1、静态代理 角色分析: 抽象角色:一般会使用接口或者抽象类来解决真实角色&…

代理模式(Proxy模式)详解

在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保…

代理模式的详细介绍

国庆期间闲来无事,写了一个简单的小程序,小程序名称叫做 IT藏经楼。目的是分享这些年自己积累的一些学习材料,方面大家查找使用,包括电子书、案例项目、学习视频、面试题和一些PPT模板。里面所有材料都免费分享。目前小程序中只发…

代理模式

代理模式 代理模式应用场景模式结构实现方式 代理模式 控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。 优点: 在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;代理对象可以扩展目标对象的功能&#x…

代理模式详解

1. 代理模式 代理模式是一种比较好理解的设计模式。简单来说就是 我们使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。 代理模式一半包含三种角色&#x…

代理模式详细讲解

文章目录 一、什么是代理模式?二、 为什么使用代理模式?三、 代理模式的实现1、静态代理1.1、 创建公共的接口1.2、 创建被代理角色1.3、 创建代理角色1.4、 创建测试类 2、动态代理的实现2.1、 使用 JDK 的 Proxy 类实现动态代理1、 创建业务接口2、 创…

一文搞懂代理模式

代理模式 前言一、代理模式是什么?二、静态代理三、动态代理1.jdk动态代理(接口代理)2.cglib动态代理 前言 一、代理模式是什么? 代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象…

手机测试耳机音质的软件,耳机音质测试软件有哪些

耳机音质测试软件并不存在,因为耳机的音质对于人来说是主观的,你认为音质好的耳机,有的人却并不认为也很正常,国内外都没有恒定的耳机音质评判标准,大多数人认为音质好的耳机,那么它十有八九实际就是好的。…

软件测试的基本理论与方法

文章目录 前言软件测试基础1. 软件测试的概念2. 软件测试的目的 测试用例1. 测试用例的概念2. 测试用例的分类3. 测试用例的治理4. 测试用例的编制及使用5. 测试需求 软件生命周期1. 问题的定义及规划2. 需求分析3. 软件设计4. 程序编码5. 软件测试6. 运行维护7. 生命周期模型 …

固态硬盘测试软件有哪些,SSD测试软件有哪些?SSD测试软件盘点

在购买了固态硬盘(SSD)后,如果对商家或官方给出的诸如读写速度等关键性数据存在质疑的话,最好的解决方法莫过于通过SSD测试软件来找寻答案。那么,SSD测试软件有哪些?SSD测试软件哪个比较好用呢?针对上述问题&#xff0…

软件工程-软件测试-测试方法

软件工程-测试方法-白盒和黑盒测试 软件工程-软件测试 软件测试方法可以分为静态测试和动态测试。 静态测试 静态测试是指被测试程序不在程序上运行,而是采用人工检测和计算机辅助金泰分析的手段对程序进行检测。 静态测试方法 (1)人工检…

软件测试方法和技术有哪些?

软件测试方法和技术有哪些?包括软件测试基础、软件测试方法、软件测试流程和规范、单元测试与集成测试、系统测试、验收测试、软件本地化测试、测试自动化及其框架、白盒测试和黑盒测试等。 软件测试方法技术   软件测试方法: 一、等价类测试方法的…

软件测试方法汇总 - 从不同角度分析软件测试方法有哪些

1、从是否关心内部结构来看 (1)白盒测试:又称为结构测试或逻辑驱动测试,是一种按照程序内部逻辑结构和编码结构,设计测试数据并完成测试的一种测试方法。 (2)黑盒测试:又称为数据驱…