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 是一个端到端的神经网络模型&…...
Canva迁移策略深度解析:应对每日5000万素材增长,从MySQL到DynamoDB的蜕变
随着数字化设计的蓬勃发展,Canva作为一款备受欢迎的在线设计平台,面临着日益增长的用户生成内容挑战。每天,平台上新增的素材数量高达5000万,这对数据库系统提出了前所未有的要求。为了应对这一挑战,Canva决定对其数据…...
nacos常见面试题(2024)
nacos永久实例与临时实例区别 nacos实例有2种,分别为临时实例(一般业务服务是临时的)和永久实例(如mysql、redis这种运维服务需要实时看到状态的设置为永久实例)。 临时实例只会缓存到服务注册列表中,下线…...
68000汇编实战01-编程基础
文章目录 简介产生背景应用领域 语言学习EASy68K帮助文档IDE使用 编程语言commentslabels开始标签指令标签位置标签 opcode 操作码常用操作码数据传送算术运算逻辑运算控制流分支跳转地址跳转子程序跳转 位操作比较堆栈操作 IO操作码其他操作码 directives 指令DC指令EQU 指令S…...
你的网站真的安全吗?如何防止网站被攻击?
你的网站被黑客攻击过,很可能不止一次! 这可不是危言耸听。微软最近发布了《2024 年微软数字防御报告》,报告中写到:“Windows 用户每天面临超过 6 亿次网络犯罪和国家级别的攻击,涵盖了从勒索软件到网络钓鱼再到身份…...
UE5 材质编辑器CheapContrast 节点
在 Unreal Engine 材质编辑器中,CheapContrast 节点是一个非常实用的节点,主要用于对图像或纹理的 对比度 进行调整,且执行效率较高,适合在性能要求较高的场景中使用。 CheapContrast 节点的作用 CheapContrast 节点通过调整输入…...
健身房小程序服务渠道开展
健身不单单是锻炼身体、保持身材,也是一种社交方式,城市里门店不少,每家都有一定流量和老客,但仅靠传统线下拉客/自然流量前往和线上朋友圈、短视频发硬广等方式还不够。 商家需要找到更多潜在目标客户,而消费者也对门…...
Java基础面试题08:Java中Exception和Error有什么区别?
在Java中,Exception 和 Error 是异常处理体系的两大核心概念。要理解它们的区别和应用,咱们可以逐步剖析。 Exception和Error的基础区别 共同点: 两者都继承自 Throwable 类,只有 Throwable 类型的实例才能被 throw 或 catch。 区…...
什么是axios?怎么使用axios封装Ajax?
学习目标 什么是axios怎么使用axios封装Ajax该如何使用Axios 封装 XHR 请求 什么是axios Axios 是一个基于 Promise 的 HTTP 客户端,它可以在浏览器和 Node.js 环境中使用。Axios 提供了简单易用的 API,用于执行各种 HTTP 请求操作,如 GET、P…...
Web前端学习_CSS盒子模型
content padding border margin <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>CSS盒子模型</title><style></style> </head> <body> <div class"demo&quo…...
JAVA项目-------医院挂号系统
1,项目目的 1、科室管理:新增科室,删除科室(如果有医生在,则不能删除该科室),修改科室。 2、医生管理:录入医生信息,以及科室信息。修改医生信息(主要是修改…...
网站建设7个基本流程/seo外包
在python中,给一个对象赋值,实际上就是对象对内存空间存储的值的引用。当我们把对象赋值给另一个变量的时候,这个变量并没有拷贝这个对象,而只是拷贝了这个对象的引用而已。一般情况下我们会通过三种方法来实现拷贝对象的引用。Py…...
台州本地做网站的/电商培训内容有哪些
新冠肺炎疫情发生以来,大家都在问:如何能够保持良好的自身免疫力? 优质蛋白可以提高人体免疫力,按照普通成年人的平均体重推荐的摄入量,每天平均摄入肉1两、鸡蛋1个、鱼1两、大豆半两、牛奶300克,就能保证身…...
王也头像 呆萌/武汉网优化seo公司
0. 引言 Tensorflow于1.7之后推出了tensorflow hub,其是一个适合于迁移学习的部分,主要通过将tensorflow的训练好的模型进行模块划分,并可以再次加以利用。不过介于推出不久,目前只有图像的分类和文本的分类以及少量其他模型 这里…...
企业内部网站制作/来宾网站seo
上次的文章中,我们简单描述了一下软件架构的概念,接下来我们描述一下软件架构中的具体细节。 软件架构 所谓软件元素,即指组成软件系统的一个最基本的模块。一个软件元素的特性在很大程度上取决于系统的类型,以及你考虑和选取软件…...
做网站 用 云主机/企业seo关键字优化
调色版本 Grade Version记录着片段的全部调色信息。将一种调色风格或效果,保存为一个调色版本,从而可在多个调色版本之间查看、比较、挑选或者渲染输出。调色版本类型本地版本Local Versions在没有创建新的调色版本之前,片段的调色信息默认记…...