Spring中动态代理设计模式

news2024/9/21 20:24:48

目录

一、什么是动态代理

二、动态代理开发步骤

2.1 搭建开发环境

2.2 具体过程

三、动态字节码技术

四、动态代理开发简化代理开发


一、什么是动态代理

其实不管是静态代理还是动态代理其本质都是一样的,都是通过代理类为目标类增加额外功能,从而方便目标类的维护,只是在实现的过程中有所区别

二、动态代理开发步骤

2.1 搭建开发环境

在动态代理开发的过程中,是需要一些依赖的,将这些依赖文件导入pom.xml文件中

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.14.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>
<dependency><groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.3</version>
</dependency>

2.2 具体过程

1)创建目标对象

在静态代理设计模式中,我们采取的是new对象的方式,这种方式是会产生耦合的,所以在动态代理的过程中使用Spring配置文件来创建对象

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>

2)添加额外功能

创建好目标类之后我们需要去添加额外功能,这里添加额外功能就不再是自己定义一个类了,而是去实现Spring中的MethodBeforeAdvice接口。实现了这个接口就可以达成在目标类之前添加额外功能。然后再配置文件中创建出这个类的对象

public class Before implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        // 在则个方法中添加额外功能
        System.out.println("----method before advice log----");
    }
}
<bean id="before" class="com.gl.demo.proxy.Before"/>

3)定义切入点

为什么要定义切入点呢?其实在类中会有许多方法,但是有的方法是不需要添加额外功能的,那么定义这个切入点就可以选择为哪些方法添加额外功能。引入一个新的aop:config标签然后再这个标签中定义切入点,这里的切入点表达式execution就决定了为哪些方法添加额外功能,这个表达式时为该类所有方法添加额外功能

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
</aop:config>

4)组装 

定义了切入点后肯定是要将额外功能添加进去的,所以这里就需要在配置文件中组装额外功能

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>
<bean id="before" class="com.gl.demo.proxy.Before"/>

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>

    <!-- 进行组装 -->
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

5)调用

通过前4步的过程所有的都已经准备好了,那最后一步获取到这个代理对象即可,但是我们发现这里根本就没有这个代理对象。那要怎么获取呢?

我们只需通过getBean标签获取到之前的目标类(原始类)对象即可。好,到了这里可能有的同学就会说了,获取目标类对象那不是白干了,其实不然,Spring已经帮我们加工好了这个类对象了,我们通过getBean获取到的这个类对象就已经是一个代理类对象了 。同时需要注意的是这个对象需要用之前实现的接口来接收(和之前实现同一个接口是一个道理)

public void test2() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
    UserService userService = (UserService) ctx.getBean("userService");
    userService.register();
    userService.login();
}

在这里我们发现额外功能的添加就已经完成了

三、动态字节码技术

有的同学就会好奇,明明没有这个代理类怎么能获取到这个代理类的对象呢?其实在Spring框架运行的时候会通过动态字节码技术,在JVM中创建这个代理类,等程序结束后随着JVM会一起消失。那么问题来了,什么是动态字节码技术?

动态字节码技术:通过第三方的动态字节码框架,在JVM中创建对应类的字节码,进而创建对象,当虚拟机结束时,动态字节码随之消失(由于使用这个技术,就不需要定义类文件,所以就不会造成静态代理中类文件过多,影响项目管理的问题

四、动态代理开发简化代理开发

初看这个动态代理开发,可能会有同学认为这不是比静态代理还要麻烦吗?静态代理我都只需要写一个代理类,这里还要写额外功能、切入点、甚至还要重新组装。其实不然,这里再创建一个类并为这个类做动态代理

public interface OrderService {
    void showOrder();
}
public class OrderServiceImpl implements OrderService{
    @Override
    public void showOrder() {
        System.out.println("OrderService核心功能");
    }
}

有了这个类之后,我想为这个类添加额外功能是不是还是要像之前那么麻烦呢?这里如果是添加已有的额外功能是不需要这么复杂的,只需要在配置文件中创建这个对象即可

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>
<bean id="before" class="com.gl.demo.proxy.Before"/>
<!-- 只需要创建这个类对象即可-->
<bean id="orderService" class="com.gl.demo.proxy.OrderServiceImpl"/>

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

然后进行测试,我们看一下这个类中的方法是否添加了额外功能

public void test3() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config2.xml");
    OrderService orderService = (OrderService) ctx.getBean("orderService");
    orderService.showOrder();
}

结果显示这个新的类中的方法也加上了相同的额外功能

那么到这里可能又会有问题了,这么一加不是所有类的所有方法都会添加上这个额外功能了?这个问题问的好!这里就可以通过切入点表达式execution来决定具体是哪个类的哪个方法添加额外功能了。。。欲知后事如何。。。

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

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

相关文章

Day7力扣打卡

打卡记录 合法分组的最少组数&#xff08;贪心&#xff09; 链接 举例说明&#xff0c;假设 c n t [ x ] 32 cnt[x]32 cnt[x]32&#xff0c; k 10 k10 k10&#xff0c;那么 32 10 10 10 2 321010102 321010102&#xff0c;多出的 2 2 2 可以分成两个 1 1 1&#xf…

Verilog基础:$fopen和$fclose系统函数、任务的使用

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 $fopen和$fclose是两个用于打开和关闭文件的系统函数、任务。最初&#xff0c;在Verilog-1995标准中&#xff0c;最多只能同时打开32个文件&#xff0c;其所使用的…

Flink部署模式及核心概念

一.部署模式 1.1会话模式&#xff08;Session Mode&#xff09; 需要先启动一个 Flink 集群&#xff0c;保持一个会话&#xff0c;所有提交的作业都会运行在此集群上&#xff0c;且启动时所需的资源以确定&#xff0c;无法更改&#xff0c;所以所有已提交的作业都会竞争集群中…

2023/10/22总结

项目上 登录注册忘记密码已经全部完善——连接数据库&#xff0c;发送验证码等 把ER图和项目功能点也给做完了&#xff08;可能后期还需要修改 &#xff0c;因为问题会在实践的时候出现&#xff09; 功能点图 刷题记录 接下来的任务是争取早日完成这个项目。

图论04-【无权无向】-图的广度优先遍历BFS

文章目录 1. 代码仓库2. 广度优先遍历图解3.主要代码4. 完整代码 1. 代码仓库 https://github.com/Chufeng-Jiang/Graph-Theory 2. 广度优先遍历图解 3.主要代码 原点入队列原点出队列的同时&#xff0c;将与其相邻的顶点全部入队列下一个顶点出队列出队列的同时&#xff0c;将…

Python基础入门例程4-NP4 读入整数数字

描述 在学会读入字符串以后&#xff0c;小白还想要读入整数&#xff0c;请你帮他使用input函数读入数字并输出数字与变量类型。 输入描述&#xff1a; 输入只有整数。 输出描述&#xff1a; 将输入的数字输出&#xff0c;同时换行输出变量类型。 示例1 输入&#xff1a; …

《算法通关村第二关黄金挑战一一K个一组反转》

《算法通关村第二关黄金挑战一一K个一组反转》 描述 每 k 个节点一组进行翻转&#xff0c;请你返回翻转后的链表。k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 解法 头插法 理解…

【超级基础版】十进制与二进制的转换

目录 一、为什么是二进制&#xff1f; 二、二进制的加法和乘法 三、二进制向十进制转换 四、十进制整数向二进制转换 五、十进制小数向二进制小数的转换 六、八进制和十六进制的引入 一、为什么是二进制&#xff1f; 我们知道电脑的数据本质上是0和1&#xff0c;就是我们…

已更新!c++第四章知识点合集(自定义函数的格式和使用方法详解, #include,函数的嵌套 递归,局部变量与全局变量的区别等等)

c知识点合集已经完成欢迎前往主页查看&#xff0c;点点赞点点关注不迷路哦 点我进入c第一章知识点合集 MYSQL知识点持续更新中 MYSQL第一章节DDL数据定义语言的操作----点我进入 MYSQL第二章节DDL-数据库操作语言 DQL-数据查询语言----点我进入 MYSQL-第三章节DCL-管理用户&…

库函数qsort的使用

在排序时&#xff0c;我们通常写的函数只能排一种固定的类型&#xff0c;那有没有一种方法可以用来对所有的数据类型&#xff0c;进行排序呢&#xff1f;库函数中的qsort函数就可以实现这种排序。 首先qsort的函数参数有四个&#xff0c;第一个是数组的起始地址(即数组名)&…

【ML】cheatsheet

LR 原理与面试题目DT, Adaboost, GBDT, xgboost 原理 细节 与 例子 https://www.cnblogs.com/createMoMo/p/12635709.html xgboost挺详细的算法原理与例子 https://zhuanlan.zhihu.com/p/660468945 着重lightgbm就xgboost的改善方向 https://zhuanlan.zhihu.com/p/366952043机器…

什么是卷积神经网络?解决了什么问题?

什么是卷积神经网络&#xff1f; 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种深度神经网络模型&#xff0c;主要用于图像识别、语音识别和自然语言处理等任务。它通过卷积层、池化层和全连接层来实现特征提取和分类。 解决了什么问…

pycharm使用Git拉取最新代码(配置了远程服务器)

首先分享一下如何在pycharm设置代理&#xff08;毕竟pull代码往往是从GitHub上&#xff09;。因为即便本地开启了代理&#xff0c;PyCharm并不会自动使用它。需要在PyCharm的设置中手动配置代理。 下面是在PyCharm中设置代理的步骤&#xff1a; 主菜单中选择File > Settin…

Node学习笔记之MySQL基本使用

使用 SQL 管理数据库 其实写接口简单来说就是操作数据库数据&#xff0c;所以我们需要学会数据库的增、删、查、改等基本操作 1. 什么是 SQL SQL&#xff08;英文全称&#xff1a;Structured Query Language&#xff09;是结构化查询语言&#xff0c;专门用来访问和处理数据…

Kubernetes技术与架构-网络 1

基于OSI网络模型&#xff0c;Kubernetes集群的网络策略包括7层负载均衡的网关路由策略&#xff0c;以及4层3层的网络IP地址策略&#xff0c;这些网络策略是保证Kubernetes集群内Pod之间的网络访问的互联互通&#xff0c;本文主要描述Kubernetes集群的网络策略的基本使用方式。 …

基于nodejs+vue旅行社网站系统

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

Linux笔记之diff和vimdiff

Linux笔记之diff和vimdiff code review! 文章目录 Linux笔记之diff和vimdiff一.diff1.1.使用diff比较文件夹1.2.使用diff比较文件1.4.colordiff——带颜色输出差异 二.vimdiff2.1.vimdiff颜色差异2.2.vimfiff调整栏宽2.3.修改颜色变谈&#xff0c;使代码可以看清楚2.4.vimdif…

[AUTOSAR][诊断管理][ECU][$14] 清除诊断相关信息

文章目录 一、简介(1)应用场景(2)清除DTC原理(3) 请求格式二、示例代码(1) 14_cls_dtc_info.c三、 常见bug大揭秘一、简介 根据ISO14119-1标准中所述,诊断服务14主要用于Client向Server(ECU)请求清除诊断相关信息。 (1)应用场景 一般而言,14诊断服务,主要应用场景…

面向对象(基础)特征一:封装性(encapsulation)

文章目录 一、介绍&#xff08;1&#xff09;封装性&#xff08;2&#xff09;权限修饰符 二、案例&#xff08;1&#xff09;案例1 三、练习&#xff08;1&#xff09;练习1&#xff08;2&#xff09;练习2&#xff08;3&#xff09;练习3&#xff08;4&#xff09;练习4 面向…

【2023年11月第四版教材】软考高项极限冲刺篇笔记(3)

8 成本管理 成本类型:可变成本、固定成本、直接成本、间接成本、机会成本、沉没成本 应急储备:成本基准内 管理成本:成本基准外 进度偏差:SV,SPI 成本管理主要是规划和控制 成本估算 类比估算 参数估算 自上而下估算 三点估算 备选方案分析 储备分析 质量成本 总资…