Java阶段三05
第3章-第5节
一、知识点
动态代理、jdk动态代理、cglib动态代理、AOP、SpringAOP
二、目标
-
理解什么是动态代理和它的作用
-
学会使用JAVA进行动态代理
-
理解什么是AOP
-
学会使用AOP
-
理解什么是AOP的切入点
三、内容分析
-
重点
-
理解什么是动态代理和它的作用
-
理解什么是AOP
-
学会使用AOP
-
-
难点
-
理解什么是AOP
-
学会使用AOP
-
四、内容
1、动态代理
1.1 什么是代理
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式,即通过代理对象访问目标对象。这样做可以在目标对象实现的基础上,增强额外的功能操作,扩展目标对象的功能
开发系统的时候,第一个版本的系统比较简陋,只需要实现基本功能,程序使用了一段时间后,准备二开,在二开的项目需求中需要对第一个版本的所有操作都做一个日志的记录,以便于后续的系统维护和分析,这个时候就可以用上代理了
1.2 什么是动态代理
-
特点:字节码随用随创建,随用随加
-
作用:不修改源码,对方法增强,在不改变原有代码的情况下,对方法进行增强
-
在程序运行的时候动态生成代理类进行增强操作
2、动态代理的使用
2.1 使用JDK实现动态代理
-
新建动态代理类,实现InvocationHandler接口
public class Proxy1 implements InvocationHandler {private Object obj = new Object();@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要执行的方法,传入一个对象,所以需要创建一个对象method.invoke(obj);return null;} }
-
使用Proxy类中的newProxyIntance方法,并且被代理类至少实现一个接口,否则不能用
-
三个参数
-
ClassLoader 类加载器,用于加载代理对象类,和被代理对象使用相同的加载器,固定写法
-
Class[] 被代理对象实现的所有接口的字节码数组,用于代理的接口,固定写法
-
InvocationHandler 动态代理方法在执行时,会调用里面的invoke方法去执行
-
public class Proxy1 implements InvocationHandler {private Object obj = new Object();// 实现一个方法,方法名可以自己定// 传入要调用的对象去调用// 调用这个方法,传入要增强的对象public Object newProxyInstance(Object obj) {// 把传进来的对象赋值给成员变量,给invoke使用this.obj = obj;// 使用Proxy类中的newProxyIntance方法return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);}
@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 要执行的方法,传入一个对象,所以需要创建一个对象method.invoke(obj);return null;} }
-
-
创建接口并实现
public interface StudentService {void queryAll(); }
-
调用
Proxy1 proxy1 = new Proxy1(); StudentServiceImpl service = new StudentServiceImpl(); // 会调用newProxyInstance返回一个新对象 StudentService service1 = (StudentService) proxy1.newProxyInstance(service); service1.queryAll();
-
重写invoke方法
调用的时候会先执行newProxyInstance方法,返回一个新的对象
调用方法的时候会执行invoke方法,在invoke方法中执行我们调用的方法,所以可以在invoke中编写我们的增强操作
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long start = System.currentTimeMillis();method.invoke(obj);// args可以传递参数// 获取参数// int id = (int)args[0];// method.invoke(obj, args);long end = System.currentTimeMillis();System.out.println(end - start);return null; }
2.2 使用cglib实现动态代理
增强的类不需要实现接口
-
引入包cglib
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> </dependency>
-
封装代理类
public class Proxy02 implements MethodInterceptor {private Object obj = new Object();// 调用这个方法,传入要增强的对象public Object newProxyInstance(Object obj) {this.obj = obj;// 字节码增强器,用来为无接口的类创建代理Enhancer enhancer = new Enhancer();// 设置要继承的类enhancer.setSuperclass(obj.getClass());// 动态代理方法在执行时,会调用里面的invoke方法去执行enhancer.setCallback(this);// 创建代理return enhancer.create();}@Overridepublic xxx {long start = System.currentTimeMillis();method.invoke(obj, objects);long end = System.currentTimeMillis();System.out.println(end - start);return null;} }
JDK实现动态代理的底层原理是基于反射,创建出来的代理对象和目标对象是兄弟关系
cglib实现动态代理的底层原理是基于继承,创建出来的代理对象和目标对象是父子关系
3、AOP
3.1 什么是AOP
AOP(Aspect Oriented Programming:面向切面编程),在不修改源代码的情况下,给程序动态统一添加功能的一种技术
作用:利用AOP对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合性,提高程序的可重用型和开发效率。
优势:减少重复代码,提高开发效率,维护方便
实现方式:使用动态代理技术
基于动态代理技术来实现功能,将功能功能提取出来,如下图,原本要写四个接口那么验证参数、日志都得在代码中写好,然后再去实现业务代码,比较繁琐,使用切面以后将验证参数、日志等功能提取出来,四个接口我们只需要通过配置就可以直接调用对应的功能,让我们能够直接专注于写业务代码
3.2 AOP相关术语
-
目标对象(Target)
目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。
-
织入(Weaving)
织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。织入可以在编译时,类加载时和运行时完成,就是指将切面代码插入到目标对象的过程。
-
切面(Aspect)
切面是一个横切关注点的模块化,一个切面能够包含同一个类型的不同增强方法,比如说事务处理和日志处理可以理解为两个切面。切面由切入点和通知组成,它既包含了横切逻辑的定义,也包括了切入点的定义。 Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
-
通知(Advice)
通知是指拦截到连接点之后要执行的代码,包括了“around”、“before”和“after”等不同类型的通知。Spring AOP框架以拦截器来实现通知模型,并维护一个以连接点为中心的拦截器链。
-
切入点(PointCut)
切入点是对连接点进行拦截的条件定义。切入点表达式如何和连接点匹配是AOP的核心,Spring缺省使用AspectJ切入点语法。 一般认为,所有的方法都可以认为是连接点,但是我们并不希望在所有的方法上都添加通知,而切入点的作用就是提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配连接点,给满足规则的连接点添加通知。可以理解为就是指切面具体织入的方法。
-
连接点(JoinPoint)
连接点(JoinPoint)指可以被切面织入的方法,如方法的调用或特定的异常被抛出。简单来说,连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。
3.3 AOP的使用
3.3.1 引入spring依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>
3.3.2 使用xml配置实现
-
把Bean交给spring容器管理
<bean id="logService" class="com.company.service.LogService"></bean>
-
使用aop:config标签表明开始AOP的配置
<aop:config></aop:config>
-
使用aop:aspect标签配置切面
id属性:给切面提供一个唯一标识
ref属性:指定通知(切面)类的Bean的id
<aop:config><aop:aspect id="logAdvice" ref="logService"> </aop:aspect> </aop:config>
-
在aop:aspect内部使用对应标签配置通知的类型
<aop:config><aop:aspect id="logAdvice" ref="logService"><aop:before><!-- 前置 --></aop:aspect> </aop:config>
-
切入点配置
method属性:用于指定logService类中哪个方法是前置通知
pointcut属性:切入点,指定切面具体织入的方法
<aop:config><aop:aspect id="logAdvice" ref="logService"><aop:before method="before" pointcut="execution(* *..*.*(..))"><!-- 前置 --></aop:aspect> </aop:config>
-
aop:before 前置通知
-
aop:after 后置通知,有异常也会执行
-
aop:after-returning 后置通知,有异常不执行
-
aop:after-throwing 切入内容抛出异常后处理异常的逻辑
<!-- XML要配置个throwing--> <aop:after-throwing method="test5" throwing="e" pointcut="execution(* *..UserService.*(..))"></aop:after-throwing> // e这个变量名要和xml配置的throwing的值一致 public void test5(JoinPoint point, Exception e) throws Throwable {System.out.println("test5");System.out.println(e.getMessage()); }
-
aop:around 环绕通知
// around 需要做特殊配置 public void test4(ProceedingJoinPoint point) throws Throwable {System.out.println("test4");point.proceed();System.out.println("test4结束"); }
-
-
配置表达式
pointcut属性:用于指定切入点表达式,该表达式指的是对业务层中哪些方法提供增强配置表达式
表达式写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
-
标准的表达式写法
public void 包名.类名.方法名()
-
访问修饰符可以省略
void 包名.类名.方法名()
-
返回值可以使用通配符,表示任意返回
* 包名.类名.方法名()
-
包名可以使用通配符,表示任意包,但是有几级包,就得写几个*
* *.*.*.类名.方法名()
-
包名可以使用*..表示当前包及其子包
* *..类名.方法名()
-
类名和方法名都可以使用通配符
* *..*.*()
-
参数列表
可以直接写数据类型
基本数据类型直接写名称 如int
引用数据类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法
* 包名.*.*(..)
<aop:config><aop:aspect id="logAdvice" ref="logService"><aop:before method="before" pointcut="execution(* *..*.*(..))"></aop:before></aop:aspect> </aop:config>
-
-
提取表达式
多个地方使用同一个表达式的时候可以提取表达式
// 单独配置切入点 <aop:config><aop:pointcut id="logPointcut" expression="execution(* *..*.*(..))"/><aop:aspect id="logAdvice" ref="logService"><aop:before method="before" pointcut-ref="logPointcut"></aop:before></aop:aspect> </aop:config>
3.3.3 使用注解实现
-
创建配置类
@Configuration @ComponentScan("com.cpmpany.aop") @EnableAspectJAutoProxy // 开启注解的方式实现AOP public class SpringConfig {}
-
创建切面类 使用 @Aspect创建切面类 @Order(int) 控制切面类的顺序
@Component @Aspect @Order(1) public class Strong {}
-
配置注解、关键字 excution (表达式)
// 要增强的逻辑 // 第一个表示返回值,*匹配所有的返回值 // 第二个表示要增强到哪个方法上 @Before("execution(* com.cpmpany.aop.UserService.queryAll())") public void start() {System.out.println("开始"); } @After("execution(* com.cpmpany.aop.UserService.queryAll())") public void end() {System.out.println("结束"); }
-
测试类
public class TestAop01 {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);UserService service = ctx.getBean(UserService.class);service.queryAll();} }
4、小结
本章节中我们学了什么是动态代理、动态代理的作用、JAVA如何实现动态代理、理解了什么是SpringAOP以及SpringAOP的使用方式,帮助我们去掌握Spring的知识点,至此,我们的Spring相关的知识点就以及学习完毕了,希望大家可以自己多多动手去学习。
下一节中,我们将会开始SSM的第二个部分SpringMVC的使用,学习什么是SpringMVC,学会如何使用SpringMVC写一个网页接口。
相关文章:

Java阶段三05
第3章-第5节 一、知识点 动态代理、jdk动态代理、cglib动态代理、AOP、SpringAOP 二、目标 理解什么是动态代理和它的作用 学会使用JAVA进行动态代理 理解什么是AOP 学会使用AOP 理解什么是AOP的切入点 三、内容分析 重点 理解什么是动态代理和它的作用 理解什么是AO…...

C# yield 关键字
文章目录 前言一、yield 关键字的语法形式及使用场景(一)yield return(二)yield break 二、yield 关键字的工作原理三、yield 关键字的优势与应用场景(一)优势(二)应用场景 前言 在 …...

SpringBoot开发——结合Nginx实现负载均衡
文章目录 负载均衡介绍介绍Nginx实现负载均衡的示例图:负载均衡策略1.Round Robin:2.Least Connections:3.IP Hash :4.Generic Hash:5.Least Time (NGINX Plus only)6.Random:Nginx+SpringBoot实现负载均衡环境准备Nginx 配置负载均衡测试负载均衡介绍 介绍 在介绍Nginx的负…...

RabbitMQ在手动消费的模式下设置失败重新投递策略
最近在写RabbitMQ的消费者,因为业务需求,希望失败后重试一定次数,超过之后就不处理了,或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的,问了kimi,按它的方法配置之后,发…...

TsingtaoAI具身智能高校实训方案通过华为昇腾技术认证
日前,TsingtaoAI推出的“具身智能高校实训解决方案-从AI大模型机器人到通用具身智能”基于华为技术有限公司AI框架昇思MindSpore,完成并通过昇腾相互兼容性技术认证。 TsingtaoAI&华为昇腾联合解决方案 本项目“具身智能高校实训解决方案”以实现高…...

【Linux】线程池设计 + 策略模式
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 线程池 1-1 ⽇志与策略模式1-2 线程池设计1-3 线程安全的单例模式1-3-1 什么是单例模式1-3-2 单例模式的特点1-3-3 饿汉实现⽅式和懒汉实现⽅式1-3-4 饿汉…...

网络原理(一):应用层自定义协议的信息组织格式 HTTP 前置知识
目录 1. 应用层 2. 自定义协议 2.1 根据需求 > 明确传输信息 2.2 约定好信息组织的格式 2.2.1 行文本 2.2.2 xml 2.2.3 json 2.2.4 protobuf 3. HTTP 协议 3.1 特点 4. 抓包工具 1. 应用层 在前面的博客中, 我们了解了 TCP/IP 五层协议模型: 应用层传输层网络层…...

Python-链表数据结构学习(1)
一、什么是链表数据? 链表是一种通过指针串联在一起的数据结构,每个节点由2部分组成,一个是数据域,一个是指针域(存放下一个节点的指针)。最后一个节点的指针域指向null(空指针的意思࿰…...
性能优化经验:关闭 SWAP 分区
关闭 SWAP 分区,特别是在性能敏感场景(如 Elasticsearch 服务)中,主要与 SWAP 的工作机制和对应用性能的影响有关。以下是详细原因: 1. SWAP 的工作机制导致高延迟 SWAP 是什么: SWAP 分区是系统将物理内存…...

SpringBoot小知识(2):日志
日志是开发项目中非常重要的一个环节,它是程序员在检查程序运行的手段之一。 1.日志的基础操作 1.1 日志的作用 编程期调试代码运营期记录信息: * 记录日常运营重要信息(峰值流量、平均响应时长……) * 记录应用报错信息(错误堆栈) * 记录运维过程数据(…...
java虚拟机——jvm是怎么去找垃圾对象的
JVM(Java虚拟机)通过特定的算法和机制来查找和识别垃圾对象,以便进行垃圾回收。以下是JVM查找垃圾对象的主要方法和步骤: 一、可达性分析法 JVM使用可达性分析法来识别垃圾对象。这种方法从一组称为“GC Roots”的对象作为起始点…...

Macos远程连接Linux桌面教程;Ubuntu配置远程桌面;Mac端远程登陆Linux桌面;可能出现的问题
文章目录 1. Ubuntu配置远程桌面2. Mac端远程登陆Linux桌面3. 可能出现的问题1.您用来登录计算机的密码与登录密钥环里的密码不再匹配2. 找不到org->gnome->desktop->remote-access 1. Ubuntu配置远程桌面 打开设置->共享->屏幕共享。勾选允许连接控制屏幕&…...

hadoop_HA高可用
秒懂HA HA概述HDFS-HA工作机制工作要点元数据同步参数配置手动故障转移自动故障转移工作机制相关命令 YARN-HA参数配置自动故障转移机制相关命令 附录Zookeeper详解 HA概述 H(high)A(avilable): 高可用,意味着必须有容错机制,不能因为集群故障…...
【MySQL】MySQL中的函数之JSON_ARRAY_APPEND
在 MySQL 8.0 及更高版本中,JSON_ARRAY_APPEND() 函数用于在 JSON 数组的指定位置追加一个或多个值。这个函数非常有用,特别是在你需要在 JSON 数组的末尾或特定位置添加新的元素时。 基本语法 JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ..…...
torch.is_nonzero(input)
torch.is_nonzero(input) input: 输入张量 若输入是 不等于零的单元素张量 则返回True,否则返回False 不等于零的单元素张量:torch.tensor([0.]) 或 torch.tensor([0]) 或 torch.tensor([False])单元素张量: 只有一个数 的张量 import torch print(t…...
文本搜索程序(Qt)
头文件 #ifndef TEXTFINDER_H #define TEXTFINDER_H#include <QWidget> #include <QFileDialog> #include <QFile> #include <QTextEdit> #include <QLineEdit> #include <QTextStream> #include <QPushButton> #include <QMess…...
使用 Python 剪辑视频的播放速度
要使用 Python 调整视频的播放速度,可以利用 moviepy 库中的 fx(特效)模块来实现这一功能。通过 moviepy.editor 中的 VideoFileClip 类和 fx.speedx 函数,可以轻松地调整视频的播放速度。 安装 moviepy 首先,确保已…...

深入理解计算机系统,源码到可执行文件翻译过程:预处理、编译,汇编和链接
1.前言 从一个高级语言到可执行程序,要经过预处理、编译,汇编和链接四个过程。大家可以思考下,为什么要有这样的过程? 我们学习计算机之处,就应该了解到,计算机能够识别的只有二进制语言(这是…...
Linux开发者的CI/CD(11)jenkins变量
文章目录 1. **环境变量 (Environment Variables)**常见的环境变量:示例:2. **构建参数 (Build Parameters)**常见的构建参数类型:示例:3 **在 `stages` 块内定义局部变量**示例:使用 `script` 步骤定义局部变量4 变量引用陷阱在 Jenkins 中,变量是自动化流程中非常重要的…...
深度学习视频编解码开源项目介绍【持续更新】
DVC (Deep Video Compression) 介绍:DVC (Deep Video Compression) 是一个基于深度学习的视频压缩框架,它的目标是通过深度神经网络来提高视频编码的效率,并降低比特率,同时尽可能保持视频质量。DVC 是一个端到端的神经网络模型&…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...