Spring 的代理开发设计
目录
编辑一、静态代理设计模式
1、为什么需要代理设计模式
2、代理设计模式
(1)概念
(2)名词解释
(3)代理开发的核心要素
(4)编码
(5)静态代理存在的问题
二、Spring 的动态代理开发
1、Spring 动态代理的概念
2、搭建开发环境
3、Spring 动态代理的开发步骤
(1)创建原始对象(目标对象)
(2)提供额外功能
(3)定义切入点
(4)组装
(5)调用
4、动态代理细节分析
三、Spring 动态代理详解
1、额外功能的详解
(1)MethodbeforeAdvice
(2)MethodInterceptor(方法拦截器)
2、切入点详解
(1)切入点表达式
1、方法切入点表达式
2、类切入点
3、包切入点
(2)切入点函数
1、execution
2、args
3、within
4、@annotation
5、切入点函数的逻辑运算
一、静态代理设计模式
1、为什么需要代理设计模式
在 JavaEE 分层开发中,哪个层次对于我们来说是最重要的?
Java 的开发思路: DAO ---> Service ---> Controller
其中最重要的是 Service ,因为做任何一个项目,写任何一段代码,最主要的目的都是为了满足用户的需求
Service 中包含了哪些代码?
Service 中 = 核心功能(几十行 上百行代码) + 额外功能(附加功能)
1、核心功能
业务运算
DAO 调用
2、额外功能
(1)不属于业务
(2)可有可无
(3)代码量小
事务、日志、性能....
额外功能 书写在 Service 中到底好不好呢?
Service 层调用者的角度(Controller):需要在 Service 中书写额外功能
软件设计者的角度:Service 中不需要额外功能(会造成代码不好维护)
现实生活中的解决方式:

我们把房东当成一个类(业务类 Service),房东提供了出租房屋的业务方法, 出租房屋的核心功能就是签合同和收钱,但是出租房屋光有核心功能是不够的,还得有一些额外功能:广告,看房。(类似于事务,日志....)
站在房东的角度来讲,它不愿意做这些额外功能了,但是房客不允许房东不做这些额外功能,要想解决这个问题,就得引入一个新的角色:中介(代理类)
中介就代替房东提供了这些额外功能:广告和看房,在这些方法中,首要的职责就是把房东曾经不干的额外功能由中介来干
但是最核心的功能,还是由房东自身来做的,这个时候对于房客来讲,既能享受到房东提供的核心功能,又能享受到中介提供的额外功能,诉求就满足了
如果有朝一日对额外功能不满意了,不需要修改原来的代码,可以直接换一个新的中介公司,让它提供一个新的额外方法,代码的维护性也就大大提高了
2、代理设计模式
(1)概念
通过代理类,为原始类增加额外的功能
好处:利于原始类的维护
(2)名词解释
1、目标类 / 原始类:也就是房东,指的是业务类(核心功能 --> 业务运算 --> DAO 的调用)
2、目标方法 / 原始方法:目标类(原始类)中的方法,就是目标方法(原始方法)
3、额外功能(附加功能):以日志,事务,性能...为代表
(3)代理开发的核心要素
代理类 = 目标类(原始类) + 额外功能 + 原始类(目标类)实现相同的接口
房东 ---> public interface UserService{m1m2}UserServiceImpl implements UserService{m1 ---> 业务运算 DAO调⽤m2}UserServiceProxy implements UserService{m1m2
}
(4)编码
//代理类的开发
public class UserServiceProxy implements UserService{//获得原始对象private UserServiceImpl userService = new UserServiceImpl();@Overridepublic void register(User user) {System.out.println("------log--------");userService.register(user);}@Overridepublic boolean login(String name, String password) {System.out.println("-------log------");return userService.login(name,password);}
}

(5)静态代理存在的问题
1、静态代理文件数量过多,会不利于项目管理
有一个 UserServiceImpl 的原始类,就要提供一个 UserServiceproxy 的代理类,与之对应的,类的数量就会成倍的增长
2、额外功能维护性差
当我们想换一个日志的实现方式的时候,很多代码都得跟着修改,所以代码的维护性非常差
二、Spring 的动态代理开发
1、Spring 动态代理的概念
概念:通过代理类,为原始类(目标类)增加额外功能
优点:利于原始类(目标类)的维护
2、搭建开发环境
引入 Spring 动态代理相关的 jar 包
<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>
3、Spring 动态代理的开发步骤
(1)创建原始对象(目标对象)
public class UserServiceImpl implements UserService{@Overridepublic void register(User user) {System.out.println("UserServiceImpl.register 业务运算 + DAO ");}@Overridepublic boolean login(String name, String password) {System.out.println("UserServiceImpl.login");return true;}
}
<bean id="userService" class="proxy.OrderServiceImpl"></bean>
(2)提供额外功能
MethodBeforeAdvice 是一个接口
我们需要把额外功能写在接口的实现中,额外功能会在原始方法执行之前运行额外功能
public class Before implements MethodBeforeAdvice {//作用:需要把运行在原始方法运行之前运行的额外功能,书写在 beofre 方法中@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("------method before advice-------");}
}
<bean id="before" class="dynamic.Before"></bean>
(3)定义切入点
切入点:额外功能加入的位置
Spring 引入切入点的目的:由程序员根据自己的需要,来决定额外功能加入给哪个原始方法
简单的测试:所有方法都作为切入点,都加入额外的功能
通过 Spring 的配置文件完成
expression :切入点表达式,要根据自己的需求来写
<aop:config>
<!-- 所有的方法,都作为切入点,加入额外功能 --><aop:pointcut id = "pc" expression = "execution(* *(..))"/></aop:config>
(4)组装
把 第二步 和 第三步 进行整合
<aop:config>
<!-- 所有的方法,都作为切入点,加入额外功能 --><aop:pointcut id = "pc" expression = "execution(* *(..))"/><!-- 组装:把切入点和额外功能进行整合 --><aop:advisor advice-ref="before" pointcut-ref = "pc"/></aop:config>
表达的含义:所有的方法都加入 before 的额外功能
(5)调用
目的:获得 Spring 工厂创建的动态代理对象,并进行调用
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");//注意:
// 1、Spring 的工厂,通过原始对象的 id 值获得的是代理对象
// 2、获得代理对象之后,可以通过声明接口类型,进行对象的存储UserService userService = (UserService) ctx.getBean("userService");userService.login();
userService.registere();
注意:
1、Spring 的工厂,通过原始对象的 id 值获得的是代理对象
2、获得代理对象之后,可以通过声明接口类型,进行对象的存储
4、动态代理细节分析
(1)Spring 创建的动态代理类在哪里?
动态代理类是 Spring 框架在运行时,通过动态字节码技术在虚拟机中创建的,运行在虚拟机内部,等程序结束后,会和虚拟机一起消失
动态字节码技术:通过第三方动态字节码框架在虚拟机中创建对应的类的字节码,进而创建对象,当虚拟机关闭,动态字节码也跟着消失
结论:动态代理,不需要定义类文件,都是 JVM 运行过程当中,动态创建的,所以不会造成静态代理中类文件数量过多影响项目管理的问题

(2)动态代理编程会简化代理的开发
在额外功能不改变的前提下,创建其它目标类(原始类)的代理对象时,只需要指定原始(目标)对象即可
(3)动态代理的维护性大大增强了
对额外功能不满意的情况下,不用进行修改,直接创建一个新的额外功能即可
三、Spring 动态代理详解
1、额外功能的详解
(1)MethodbeforeAdvice
1、MethodBeforeAdvice 接口作用:额外功能在运行在原始方法执行之前,进行额外功能操作。

2、before 方法的 3 个参数在实战中 ,该如何使用?
before 方法的参数在实战中,会根据需要来进行使用,不一定都会用到,也有可能都不用
Servlet{service(HttpRequest request,HttpResponse response){request.getParameter("name") -->response.getWriter() --->} }
(2)MethodInterceptor(方法拦截器)
和 MethodBeforeAdvice 的区别:
MethodBeforeAdvice 只能运行在原始方法执行之前,相对来讲,功能比较单一
MethodInterceptor,可以运行在原始方法执行之前,也可以运行在原始方法执行之后,灵活性更高
注意:在这里我们选择 aopllicance 的包提供的接口

public class Arround implements MethodInterceptor {/*invoke 方法的作用: 额外功能书写在 invoke额外功能可以运行在原始方法之前,原始方法之后,原始方法的之前和之后要先提前确定原始方法如何运行:参数:MethodInvocation (类似前面提到的的Method)代表额外功能所增加给的原始方法invocation.proceed() 就代表对应的方法的执行返回值:Object:原始方法的返回值*/@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("-----额外功能 log----");Object ret = invocation.proceed();return ret;}
}
<bean id="arround" class="dynamic.Arround"></bean><aop:config><!-- 所有的方法,都作为切入点,加入额外功能 --><aop:pointcut id = "pc" expression = "execution(* *(..))"/><!-- 组装:把切入点和额外功能进行整合 --><aop:advisor advice-ref="arround" pointcut-ref = "pc"/></aop:config>
2、切入点详解
切入点:决定了额外功能加入的位置
<aop:pointcut id="pc" expression="execution(* *(..))"/>
exection(* *(..)) ---> 匹配了所有⽅法
1、execution : 切入点函数
2、* *(..) 切入点表达式
(1)切入点表达式
1、方法切入点表达式
* *(..) ---> 所有方法

* ---> 修饰符 返回值
* ---> ⽅法名
()---> 参数表
..---> 对于参数没有要求 (参数有没有,参数有⼏个都⾏,参数是什么类型的都⾏)
定义 login 方法作为切入点
* login(..)
定义 login 方法,且 login 方法有两个字符串类型的参数,作为切入点
* login(String,String)
注意:如果参数的类型不是 java.lang 包当中的,那必须写类型的权限定名
* regidter(proxy.User)
2、类切入点
指定类作为切入点(额外功能加入的位置),自然这个类中的所有方法,都会加上对应的额外功能了
<aop:config><!-- 类的方法,都作为切入点,加入额外功能 --><aop:pointcut id = "pc" expression = "execution(* proxy.UserServiceImpl.*(..))"/><!-- 组装:把切入点和额外功能进行整合 --><aop:advisor advice-ref="arround" pointcut-ref = "pc"/></aop:config>
类中所有方法加入额外功能:
## 类中所有的方法都加入了额外功能
* proxy.userService.*(..)
忽略包:
## 类只存在一层包
* *.UserServiceImpl.*(..)## 类存在多层包
* *..UserServiceImpl.*(..)
3、包切入点
指定包作为额外功能加入的位置,自然包中的所有类及其方法都会加入额外的功能

# 切入点包中的所有类,必须在 proxy 中,不能在 proxy 包的子包中* proxy.*.*(..)
# 切入点当前包及当前包的子包都生效* proxy..*.*(..)
(2)切入点函数
切入点函数:用于执行切入点表达式
1、execution
execution 是最为重要的切入点函数,功能最全
可以执行:方法切入点表达式,类切入点表达式,包切入点表达式
弊端:execution 在执行切入点表达式的时候,书写麻烦
注意:其它的切入点函数,仅仅简化的是 execution 书写复杂度,功能上完全一致
2、args
作用:主要用于函数(方法)参数的匹配
切入点:方法的参数必须得是两个字符串类型的参数
execution( * *(String,String) )args(String,String)
3、within
作用:主要用于进行类、包切入点表达式的匹配
切入点: UserServiceImpl
execution( * *..UserService.*(..) )within( * .. UserServiceImpl )execution(* proxy..*.*(..) )within( proxy.. )
4、@annotation
作用:为具有特殊注解的方法加入额外功能
< aop: pointcut id = "" expression = "@annotation(Log)"/>
5、切入点函数的逻辑运算
指的是:整合多个切入点函数一起配合工作,进而完成更为复杂的需求
and 与操作
案例:方法名:login 参数:String ,String
execution ( * login(String,String) )execution ( * login(..) ) and args( String,String )
注意:与操作,不能用于同种类型的切入点函数
例如: execution and execution
or 或操作
案例:register⽅法 和 login⽅法作为切⼊点
execution(* login(..)) or execution(* register(..))
相关文章:
Spring 的代理开发设计
目录 编辑一、静态代理设计模式 1、为什么需要代理设计模式 2、代理设计模式 (1)概念 (2)名词解释 (3)代理开发的核心要素 (4)编码 (5)静态代理存在…...
实现注册手机号用户
1、使用Post异步发送请求(发送短信),离焦事件触发时判断 <script src"layer/layer.js"></script><!--离焦事件--><script type"text/javascript" th:inline"javascript">$("#use…...
【2023年11月第四版教材】第15章《风险管理》(第三部分)
第15章《风险管理》(第三部分) 5 过程1-规划风险管理6 过程2-识别风险6.1 识别风险★★★6.2 数据收集★★★6.3 数据分析★★★ 7 过程3-实施定性风险分析7.1 实施定性风险分析7.2 数据分析★★★7.3 数据表现★★★7.4 项目文件(更新&#…...
datart导入hive连接包
datart读取hive数据时,需要先在datart的lib目录下导入hive jdbc相关的包,这里面有几个坑记录下: 1.和springboot中commons-lang3冲突 2.hive中带的jetty和springboot冲突 3.hive jdbc的包的版本号一定要小于登录hive服务端的版本ÿ…...
2023美团秋招一面面经-已过
批处理批处理一个sql下的若干条sql,如何提高速度,如果要分片的话如何分片 1.使用数据库的批处理功能来执行多个 SQL 语句。这可以减少每个 SQL 语句的通信开销。JDBC 中的 addBatch() 和 executeBatch() 方法可以用来执行批处理操作。 在程序开始时候设…...
ARM Day2
目录 实现1-100的累加 思维导图 实现1-100的累加 .text .globl _start _start:mov r1,#0x64mov r2,#0x1mov r4,#0x1 going:cmp r1,r4bcc endleaddcs r3,r3,r4add r4,r4,r2b going endle:stop:b stop .end思维导图...
手把手教你制作独特优惠促销微传单
您是否曾经想要为自己的业务或活动制作一张吸引人的微传单?以下是一份简单易懂的微传单制作教程,帮助您在短短四步内打造出精美的宣传海报。 1. 登录乔拓云,点击【微传单】 首先,打开乔拓云网站并点击【微传单】选项。您将进入一个…...
Qt-QImage-convertTo-copy-convertToFormat-格式转换
文章目录 1.copy2.convertToFormat3.QPainter4.总结 1.copy 深度复制图像格式数据,可以指定区域。 QImage copy(const QRect &rect QRect()) const;inline QImage copy(int x, int y, int w, int h) const{ return copy(QRect(x, y, w, h)); }2.convertToForm…...
asp.net core automapper的使用
1.安装automapper的nuget包 AutoMapper.Extensions.Microsoft.DependencyInjection 2.创建需要映射的类和转换后的类 public class studto{public int sn { get; set; }public string name { get; set; }public string sex { get; set; }public int age { get; set; }public s…...
自学WEB后端03-Node.js 语法
学习后端路线: JavaScript 基础语法 Node,js 内置 API 模块 (fs、 path、 http等) 第三方 API 模块 (express、mysql等) 今天主要回顾下Node.js 语法 Node.js 是基于 Chrome V8 引擎的 JavaScript 运行环境,它提供了一种能够在服务器端运行 JavaScr…...
对象数组合并和去重
数组去重: 普通字符串/数字数组去重: 1. 利用Set的特性 > new Set(arr) 2. for遍历, indexOf判断是否存在 3. 利用对象去重, 因为对象的key有唯一性 数组合并: 可以使用克隆(克隆, 深克隆的那些方法) 对象数组去重: for循环, find或者findIndex判断是否存在, 然后不存…...
【AI语言模型】阿里推出音视频转文字引擎
一、前言 阿里的音视频转文字引擎可以正式使用,用户可体验所有AI功能,含全文概要、章节速览、发言总结等高阶AI功能。通过阿里云主账号登录,可享受以下权益: 每日登录,自动获得2小时转写时长; 每邀请1名好…...
YOLOv5改进D-LKA:在D-LKA结构的基础上进行多种改进结构,同时拥有Attention和大卷积核的能力,高效改进
💡本篇内容:YOLOv5改进D-LKA:在D-LKA结构的基础上进行多种改进结构,同时拥有Attention和大卷积核的能力,高效改进 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv5 按步骤操作运行改进后的代码即可 💡本文提出改进 原创 方式:二次创新,YOLOv5专属 论文理论部…...
Java项目-Spring Boot的生鲜网上交易系统
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 1 简介2 技术栈3 系统功能4 功能设计5系统详细设计5.1系统功能模块5.2后台功能模块5\.2\.1用户功…...
MySQL - group by分组查询 (查询操作 三)
功能介绍 group by: 对数据进行分组和聚合操作(可以操作单字段和多字段) having:过滤group by的结果,也就是在分组后添加筛选条件 基础语法 select 字段列表 from 表名 [ where 条件 ] group by 分组字段名 [ having ]; where 和 having的区…...
96.qt qml-http之XMLHttpRequest介绍详解使用
在QML中我们可以通过XMLHttpRequest 来实现http/https访问网络接口,接下来我们先来学习XMLHttpRequest类的常用部分、 由于QML的XMLHttpRequest少部分参数是没有的,所以本章来单独讲解下。下章我们来实现旋转请求按钮以及通用的JSON请求模板方法 1.XMLHttpRequest初步使用 …...
代码随想录算法训练营第五十天 | 123.买卖股票的最佳时机III 188. 买卖股票的最佳时机 IV
1. 买卖股票的最佳时机 III 123. 买卖股票的最佳时机 III - 力扣(LeetCode) * 定义 5 种状态: * 0: 没有操作, 1: 第一次买入, 2: 第一次卖出, 3: 第二次买入, 4: 第二次卖出 class Solution {public int maxProfit(int[] prices) {int length prices.l…...
详解window.print(),实现长列表打印分页
相信大家平时做项目时,打印需求很常见,但想把打印做好,还是要花点时间的。特别是长列表要分页的情况。 我们知道浏览原生 API window.print() 可以用于印当前窗口(window.document)视图内容。调用此方法会产生一个打印…...
使用Chatgpt编写的PHP数据库pdo操作类(增删改查)
摘要 将PDO封装成PHP类进行调用有很多好处,包括: 1、封装性和抽象性: 通过将PDO封装到一个类中,您可以将数据库操作逻辑与应用程序的其他部分分离开来,提高了代码的组织性和可维护性。这样,您只需在一个地…...
蓝桥杯2023年第十四届省赛真题-异或和之和--题解
目录 蓝桥杯2023年第十四届省赛真题-异或和之和 题目描述 输入格式 输出格式 样例输入 样例输出 【代码实现】 大家觉得写得可以的话,可以加入QQ群907575059. 蓝桥杯2023年第十四届省赛真题-异或和之和 时间限制: 3s 内存限制: 320MB 提交: 241 解决: 66 …...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

