代理模式简述

目录

一、主要角色

二、类型划分

三、静态代理

示例

缺点

四、动态代理

JDK动态代理

示例

 缺点

CGLib动态代理

导入依赖

示例

五、Spring AOP


        代理模式是一种结构型设计模式,通过代理对象控制对目标对象的访问,可在不改变目标对象情况下增强其功能,隐藏实现细节。

一、主要角色

  • Subject(业务接口类):可以是抽象类或接口
  • RealSubject(业务实现类):具体的业务执行,即被代理的对象
  • Proxy(代理类):RealSubject的代理

二、类型划分

根据代理的创建时期,可分为静态代理和动态代理

  • 静态代理:由程序员创建或工具自动生成代理类源代码并编译,程序运行前代理类的字节码文件已经存在;
  • 动态代理:在程序运行时运用反射机制动态创建而成

为方便下面的讲解,我们先提前创建业务接口类和业务实现类

//业务接口类
public interface HouseSubject {void rentHouse();
}
//业务实现类(被代理类)
public class RealHouseSubject implements HouseSubject {@Overridepublic void rentHouse() {System.out.println("我是房东,我出租房子");}
}

三、静态代理

示例
//代理类
public class HouseProxy implements HouseSubject{//中介出售房子前要先有房东的授权private HouseSubject houseSubject;public HouseProxy(HouseSubject houseSubject) {this.houseSubject = houseSubject;}@Overridepublic void rentHouse() {System.out.println("我是中介,我开始代理房东出租房子");houseSubject.rentHouse();System.out.println("我是中介,代理结束");}
}

使用代理类执行

public class Main {public static void main(String[] args) {//创建代理对象HouseSubject subject=new HouseProxy(new RealHouseSubject());subject.rentHouse();}
}

缺点
  • 为每个被代理类编写代理类,代码冗余,随着业务的发展,类数量膨胀,项目管理难度增大
  • 被代理类接口变化时,所有相关代理类都需修改,易出错,可维护性差
  • 只能服务特定被代理类,难以应对新类和多变的额外逻辑需求,缺乏灵活性

四、动态代理

JDK动态代理
示例

自定义JDKInvocationHandler 并重写invoke(),在invoke()中会调用目标方法,并自定义一些处理逻辑

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;//实现 InvocationHandler接口可以被代理对象的方法进行功能增强
@Slf4j
public class JDKInvocationHandler implements InvocationHandler {//目标类private Object target;public JDKInvocationHandler(Object target) {this.target = target;}/*** 调用目标方法,并对方法进行增强* @param proxy 代理对象* @param method 代理对象需要实现的方法* @param args method方法所对应的参数*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log.info("JDK动态代理开始");//调用目标函数Object result=method.invoke(target,args);log.info("JDK动态代理结束");return null;}
}

创建代理对象,执行逻辑 

import java.lang.reflect.Proxy;public class Main {public static void main(String[] args) {RealHouseSubject target=new RealHouseSubject();//通过被代理类、被代理类实现的接口、方法调用处理器来创建一个代理类/***  ClassLoader loader 类加载器,用于加载代理对象*  Class<?>[] interfaces 被代理类实现的一些接口(jdk只能代理实现了接口的类)*  java.lang.reflect.InvocationHandler h 实现了InvocationHandler接口的对象*/HouseSubject proxy=(HouseSubject) Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{HouseSubject.class},new JDKInvocationHandler(target));//使用代理类proxy.rentHouse();}
}

 缺点

只能代理实现了接口的类,不能代理普通类

CGLib动态代理

导入依赖
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>
示例
import lombok.extern.slf4j.Slf4j;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;@Slf4j
public class CGLibMethodInterceptor implements MethodInterceptor {private Object target;public CGLibMethodInterceptor(Object target) {this.target = target;}/**** @param o 被代理的对象* @param method 目标方法* @param objects 方法入参* @param methodProxy 用于调用原始方法* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {//代理增强内容System.out.println("CGLib代理开始");//通过反射调用被代理的方法Object retVal=methodProxy.invoke(target,objects);System.out.println("CGLib代理结束");return retVal;}
}
import net.sf.cglib.proxy.Enhancer;public class Main {public static void main(String[] args) {HouseSubject target=new RealHouseSubject();HouseSubject proxy= (HouseSubject)Enhancer.create(target.getClass(),new CGLibMethodInterceptor(target));proxy.rentHouse();}
}

五、Spring AOP

Spring AOP是基于动态代理实现的,动态代理有JDK和CGLIB两种方式,运行时使用哪种方式与项目配置和代理的对象有关。

proxy-target-class="false"情况下,若代理对象实现接口,默认使用JDK动态代理;若未实现接口,则会用CGLIB动态代理。当然,即便对象实现接口,也能通过xml配置proxy-target-class="true"或在配置类上使用注解@EnableAspectJAutoProxy(proxyTargetClass = true) 强制使用CGLIB动态代理。

Spring Boot 2.X开始默认使用CGLIB代理,也就是proxy-target-class="true"。

二者各有优劣,需依项目实际情况抉择。JDK动态代理优势在于基于Java原生支持,无需额外依赖,性能较好,适用于对性能要求高且目标对象有接口的场景;但是只能代理实现了接口的对象。

CGLIB动态代理优势在于能代理无接口的普通类,功能更强大、灵活性更高;但是需额外注入依赖,且通过继承创建代理,若类被final修饰则无法代理,生成代理对象的性能开销相对较大。

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

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

相关文章

每日一题——云服务计费问题

云服务计费问题&#xff08;哈希表 排序&#xff09;| 附详细 C源码解析 一、题目描述二、输入描述三、输出描述四、样例输入输出输入示例&#xff1a;输出示例&#xff1a;说明&#xff1a; 五、解题思路分析六、C实现源码详解&#xff08;完整&#xff09;七、复杂度分析 一…

【JVM】运行时数据区域

文章目录 1. 程序计数器补充 2. 虚拟机栈2.1 栈帧1. 局部变量表2. 操作数栈3. 动态链接4. 方法返回地址补充 3. 本地方法栈4. 堆5. 方法区静态常量池&#xff08;Class常量池&#xff09;运行时常量池字符串常量池&#xff08;1&#xff09;位置变化&#xff08;2&#xff09;放…

day28图像处理OpenCV

文章目录 一、图像预处理4 边缘填充4.1 边界复制&#xff08;BORDER_REPLICATE&#xff09;4.2 边界反射&#xff08;BORDER_REFLECT&#xff09;4.3 边界反射101&#xff08;BORDER_REFLECT_101&#xff09;4.4 边界常数&#xff08;BORDER_CONSTANT&#xff09;4.5 边界包裹&…

C++ Json-Rpc框架-3项目实现(2)

一.消息分发Dispatcher实现 Dispatcher 就是“消息分发中枢”&#xff1a;根据消息类型 MType&#xff0c;把消息派发给对应的处理函数&#xff08;Handler&#xff09;执行。 初版&#xff1a; #pragma once #include "net.hpp" #include "message.hpp"n…

C++算法优化实战:破解性能瓶颈,提升程序效率

C算法优化实战&#xff1a;破解性能瓶颈&#xff0c;提升程序效率 在现代软件开发中&#xff0c;算法优化是提升程序性能的关键手段之一。无论是在高频交易系统、实时游戏引擎&#xff0c;还是大数据处理平台&#xff0c;算法的高效性直接关系到整体系统的性能与响应速度。C作…

【PostgreSQL教程】PostgreSQL 特别篇之 语言接口连接PHP

博主介绍:✌全网粉丝22W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。 感兴趣的可…

山东大学软件学院创新项目实训开发日志(12)之将对话记录保存到数据库中

在之前的功能开发中&#xff0c;已经成功将deepseekAPI接口接入到springbootvue项目中&#xff0c;所以下一步的操作是将对话和消息记录保存到数据库中 在之前的开发日志中提到数据库建表&#xff0c;所以在此刻需要用到两个表&#xff0c;conversation表和message表&#xff…

Spring-注解编程

注解基础概念 1.什么是注解编程 指的是在类或者方法上加入特定的注解(XXX) 完成特定功能的开发 Component public classXXX{} 2.为什么要讲注解编程 1.注解开发方便 代码简洁 开发速度大大提高 2.Spring开发潮流 Spring2.x引入注解 Spring3.x完善注解 Springboot普及 推广注解…

Dify智能体平台源码二次开发笔记(5) - 多租户的SAAS版实现(2)

目录 前言 用户的查询 controller层 添加路由 service层 用户的添加 controller层 添加路由 service层-添加用户 service层-添加用户和租户关系 验证结果 结果 前言 完成租户添加功能后&#xff0c;下一步需要实现租户下的用户管理。基础功能包括&#xff1a;查询租…

基于若依的ruoyi-vue-plus的nbmade-boot在线表单的设计(一)架构方面的设计

希望大家一起能参与我的新开源项目nbmade-boot: 宁波智能制造低代码实训平台 主要目标是类似设计jeecgboot那样的online表单功能,因为online本身没有开源这部分代码,而我设计这个是完全开源的,所以希望大家支持支持,开源不容易。 1、数据库方面设计考虑 是在原来gen_table和…

WebFlux应用中获取x-www-form-urlencoded数据的六种方法

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

[Python基础速成]1-Python规范与核心语法

本系列旨在快速掌握Python&#xff0c;实现能够快速阅读和理解 Python 代码&#xff0c;并在可查阅语法的情况下进行 AI 学习。 本篇先了解一下Python基础知识。 本篇内容较菜鸟教程有所删减、方便快速构建大纲&#xff0c;且加入了PEP 8规范说明等有助于理解和编写代码的说明。…

农民剧团的春天与改变之路

杨天义&#xff0c;男&#xff0c;1966年9月生&#xff0c;中共党员&#xff0c;江西省吉安市吉水县水南农民剧团团长。 杨天义从废品收购起家&#xff0c;凭借自身的努力和奋斗&#xff0c;自筹资金100余万元建设了水南镇的第一座影剧院&#xff0c;组建了江西省吉安市吉水县…

python asyncio 的基本使用

1、引言 asyncio 是 Python 标准库中的一个库&#xff0c;提供了对异步 I/O 、事件循环、协程和任务等异步编程模型的支持。 asyncio 文档 2、进程、线程、协程 线程 线程是操作系统调度的基本单位&#xff0c;同一个进程中的多个线程共享相同的内存空间。线程之间的切换由操…

Leedcode刷题 | Day30_贪心算法04

一、学习任务 452. 用最少数量的箭引爆气球代码随想录435. 无重叠区间763. 划分字母区间 二、具体题目 1.452用最少数量的箭引爆气球452. 用最少数量的箭引爆气球 - 力扣&#xff08;LeetCode&#xff09; 在二维空间中有许多球形的气球。对于每个气球&#xff0c;提供的输…

Ant Design Vue 表格复杂数据合并单元格

Ant Design Vue 表格复杂数据合并单元格 官方合并效果 官方示例 表头只支持列合并&#xff0c;使用 column 里的 colSpan 进行设置。 表格支持行/列合并&#xff0c;使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时&#xff0c;设置的表格不会渲染。 <temp…

C++ 标准库中的 <algorithm> 头文件算法总结

C 常用 <algorithm> 算法概览 C 标准库中的 <algorithm> 头文件提供了大量有用的算法&#xff0c;主要用于操作容器&#xff08;如 vector, list, array 等&#xff09;。这些算法通常通过迭代器来操作容器元素。 1. 非修改序列操作 std::all_of, std::any_of, s…

程序化广告行业(84/89):4A广告代理公司与行业资质解读

程序化广告行业&#xff08;84/89&#xff09;&#xff1a;4A广告代理公司与行业资质解读 大家好&#xff01;在探索程序化广告行业的道路上&#xff0c;每一次知识的分享都是我们共同进步的阶梯。一直以来&#xff0c;我都希望能和大家携手前行&#xff0c;深入了解这个充满机…

deepin使用autokey添加微信快捷键一键显隐ctrl+alt+w

打开deepin商店&#xff0c;搜索快捷键&#xff0c;找到autokey 快捷键管理&#xff0c;点击安装 点击右键新建文件夹 点击右键新建脚本 打开脚本并添加以下内容 import subprocess import time# ------------------ 配置项 ------------------ WM_CLASS "wechat…

文件内容课堂总结

Spark SQL是Spark用于结构化数据处理的模块&#xff0c;前身是Shark。Shark基于Hive开发&#xff0c;虽提升了SQL-on-Hadoop效率&#xff0c;但对Hive依赖过多。2014年6月1日Shark项目停止开发&#xff0c;团队将资源投入Spark SQL项目。Spark SQL具有诸多优点&#xff0c;如摆…