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 是一个端到端的神经网络模型&…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...

Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...