吃透 Spring 系列—AOP部分
目录
◆ AOP 简介
- AOP的概念
- AOP思想的实现方案
- 模拟AOP的基础代码
- AOP相关概念
◆ 基于xml配置的AOP
- xml方式AOP快速入门
- xml方式AOP配置详解
- xml方式AOP原理剖析
◆ 基于注解配置的AOP
- 注解方式AOP基本使用
- 注解方式AOP配置详解
- 注解方式AOP原理剖析
◆ 基于AOP的声明式事务控制
- Spring事务编程概述
- 搭建测试环境
- 基于xml声明式事务控制
- 基于注解声明式事务控制
◆ AOP 简介
- AOP的概念
AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程
- AOP思想的实现方案
动态代理技术,在运行期间,对目标对象的方法进行增强,代理对象同名方法内可以执行原有逻辑的同时嵌入执行其他增强逻辑或其他对象的方法
- 模拟AOP的基础代码
其实在之前学习BeanPostProcessor时,在BeanPostProcessor的after方法中使用动态代理对Bean进行了增强,实际存储到单例池singleObjects中的不是当前目标对象本身,而是当前目标对象的代理对象Proxy,这样在调用目标对象方法时,实际调用的是代理对象Proxy的同名方法,起到了目标方法前后都进行增强的功能,对该方式进行一下优化,将增强的方法提取出去到一个增强类中,且只对com.itheima.service.impl包下的任何类的任何方法进行增强
- AOP相关概念
◆ 基于xml配置的AOP
- xml方式AOP快速入门
前面自己编写的AOP基础代码还是存在一些问题的,主要如下:
● 被增强的包名在代码写死了
● 通知对象的方法在代码中写死了
通过配置文件的方式去解决上述问题
● 配置哪些包、哪些类、哪些方法需要被增强
● 配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强
配置方式的设计、配置文件(注解)的解析工作,Spring已经帮封装好了
xml方式配置AOP的步骤:
1、导入AOP相关坐标;
Spring-context坐标下已经包含spring-aop的包了,所以就不用额外导入了
2、准备目标类、准备增强类,并配置给Spring管理;
3、配置切点表达式(哪些方法被增强);
4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)
- xml方式AOP配置详解
xml配置AOP的方式还是比较简单的,下面看一下AOP详细配置的细节:
● 切点表达式的配置方式
● 切点表达式的配置语法
● 通知的类型
● AOP的配置的两种方式
切点表达式的配置方式有两种,直接将切点表达式配置在通知上,也可以将切点表达式抽取到外面,在通知上进行引用
切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:
其中,
● 访问修饰符可以省略不写;
● 返回值类型、某一级包名、类名、方法名 可以使用 * 表示任意;
● 包名与类名之间使用单点 . 表示该包下的类,使用双点 .. 表示该包及其子包下的类;
● 参数列表可以使用两个点 .. 表示任意参数。
切点表达式举几个例子方便理解
AspectJ的通知由以下五种类型
通知名称 | 配置方式 | 执行时机 |
前置通知 | < aop:before > | 目标方法执行之前执行 |
后置通知 | < aop:after-returning > | 目标方法执行之后执行,目标方法异常时,不在执行 |
环绕通知 | < aop:around > | 目标方法执行前后执行,目标方法异常时,环绕后方法不在执行 |
异常通知 | < aop:after-throwing > | 目标方法抛出异常时执行 |
最终通知 | < aop:after > | 不管目标方法是否有异常,最终都会执行 |
环绕通知
异常通知,当目标方法抛出异常时,异常通知方法执行,且后置通知和环绕后通知不在执行
最终通知,类似异常捕获中的finally,不管目标方法有没有异常,最终都会执行的通知
通知方法在被调用时,Spring可以为其传递一些必要的参数
参数类型 | 作用 |
JoinPoint | 连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息 |
ProceedingJoinPoint | JoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法 |
Throwable | 异常对象,使用在异常通知中,需要在配置文件中指出异常对象名称 |
JoinPoint 对象
ProceedingJoinPoint对象
Throwable对象
AOP的另一种配置方式,该方式需要通知类实现Advice的子功能接口
Advice的子功能接口
例如:通知类实现了前置通知和后置通知接口
切面使用advisor标签配置
又例如:通知类实现了方法拦截器接口
切面使用advisor标签配置
使用aspect和advisor配置区别如下:
1)配置语法不同:
2)通知类的定义要求不同,advisor 需要的通知类需要实现Advice的子功能接口:
aspect 不需要通知类实现任何接口,在配置的时候指定哪些方法属于哪种通知类型即可,更加灵活方便:
3)可配置的切面数量不同:
● 一个advisor只能配置一个固定通知和一个切点表达式;
● 一个aspect可以配置多个通知和多个切点表达式任意组合,粒度更细。
4)使用场景不同:
● 如果通知类型多、允许随意搭配情况下可以使用aspect进行配置;
● 如果通知类型单一、且通知类中通知方法一次性都会使用到的情况下可以使用advisor进行配置;
● 在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如后面要学习的Spring事务控制的配置;
由于实际开发中,自定义aop功能的配置大多使用aspect的配置方式,所以主要讲解aspect的配置,advisor是为了后面Spring声明式事务控制做铺垫,此处了解即可。
- xml方式AOP原理剖析
通过xml方式配置AOP时,引入了AOP的命名空间,根据讲解的,要去找spring-aop包下的META-INF,在去找spring.handlers文件
最终加载的是 AopNamespaceHandler,该Handler的init方法中注册了config标签对应的解析器
以ConfigBeanDefinitionParser作为入口进行源码剖析,最终会注册一个AspectJAwareAdvisorAutoProxyCreator进入到Spring容器中,那该类作用是什么呢?看一下集成体系图
AspectJAwareAdvisorAutoProxyCreator 的上上级父类AbstractAutoProxyCreator中的postProcessAfterInitialization方法
通过断点方式观察,当bean是匹配切点表达式时,this.wrapIfNecessary(bean, beanName, cacheKey)返回的是一个JDKDynamicAopProxy
可以在深入一点,对wrapIfNecessary在剖析一下,看看是不是熟知的通过JDK的
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 的方式创建的代理对象呢?经过如下一系列源码跟踪
动态代理的实现的选择,在调用getProxy() 方法时,我们可选用的 AopProxy接口有两个实现类,如上图,这两种都是动态生成代理对象的方式,一种就是基于JDK的,一种是基于Cglib的
代理技术 | 使用条件 | 配置方式 |
JDK 动态代理技术 | 目标类有接口,是基于接口动态生成实现类的代理对象 | 目标类有接口的情况下,默认方式 |
Cglib 动态代理技术 | 目标类无接口且不能使用final修饰,是基于被代理对象动态生成子对象为代理对象 | 目标类无接口时,默认使用该方式;目标 |
下面看一下Cglib基于超类的动态代理
◆ 基于注解配置的AOP
- 注解方式AOP基本使用
Spring的AOP也提供了注解方式配置,使用相应的注解替代之前的xml配置,xml配置AOP时,主要配置了三部分:目标类被Spring容器管理、通知类被Spring管理、通知与切点的织入(切面),如下:
目标类被Spring容器管理、通知类被Spring管理
配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么
注解@Aspect、@Around需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj的自动代理
如果核心配置使用的是配置类的话,需要配置注解方式的aop自动代理
- 注解方式AOP配置详解
各种注解方式通知类型
切点表达式的抽取,使用一个空方法,将切点表达式标注在空方法上,其他通知方法引用即可
- 注解方式AOP原理剖析
之前在使用xml配置AOP时,是借助的Spring的外部命名空间的加载方式完成的,使用注解配置后,就抛弃了<aop:config>标签,而该标签最终加载了名AspectJAwareAdvisorAutoProxyCreator的BeanPostProcessor ,最终,在该BeanPostProcessor中完成了代理对象的生成。
同样,从aspectj-autoproxy标签的解析器入手
而AspectJAutoProxyBeanDefinitionParser代码内部,最终也是执行了和xml方式AOP一样的代码
如果使用的是核心配置类的话
查看@EnableAspectJAutoProxy源码,使用的也是@Import导入相关解析类
使用@Import导入的AspectJAutoProxyRegistrar源码,一路追踪下去,最终还是注册了AnnotationAwareAspectJAutoProxyCreator 这个类
◆ 基于AOP的声明式事务控制
- Spring事务编程概述
事务是开发中必不可少的东西,使用JDBC开发时,我们使用connnection对事务进行控制,使用MyBatis时,我们使用SqlSession对事务进行控制,缺点显而易见,当我们切换数据库访问技术时,事务控制的方式总会变化,Spring 就将这些技术基础上,提供了统一的控制事务的接口。Spring的事务分为:编程式事务控制 和 声明式事务控制
事务控制方式 | 解释 |
编程式事务控制 | Spring提供了事务控制的类和方法,使用编码的方式对业务代码进行事务控制,事务控制代码和业务操作代码耦合到了一起,开发中不使用 |
声明式事务控制 | Spring将事务控制的代码封装,对外提供了Xml和注解配置方式,通过配置的方式完成事务的控制,可以达到事务控制与业务操作代码解耦合,开发中推荐使用 |
Spring事务编程相关的类主要有如下三个
事务控制相关类 | 解释 |
平台事务管理器 PlatformTransactionManager | 是一个接口标准,实现类都具备事务提交、回滚和获得事务对象的功能,不同持久层框架可能会有不同实现方案 |
事务定义 TransactionDefinition | 封装事务的隔离级别、传播行为、过期时间等属性信息 |
事务状态 TransactionStatus | 存储当前事务的状态信息,如果事务是否提交、是否回滚、是否有回滚点等 |
- 搭建测试环境
搭建一个转账的环境,dao层一个转出钱的方法,一个转入钱的方法,service层一个转账业务方法,内部分别调用dao层转出钱和转入钱的方法,准备工作如下:
● 数据库准备一个账户表tb_account;
● dao层准备一个AccountMapper,包括incrMoney和decrMoney两个方法;
● service层准备一个transferMoney方法,分别调用incrMoney和decrMoney方法;
● 在applicationContext文件中进行Bean的管理配置;
● 测试正常转账与异常转账。
- 基于xml声明式事务控制
结合上面学习的AOP的技术,就可以想到,可以使用AOP对Service的方法进行事务的增强。
● 目标类:自定义的AccountServiceImpl,内部的方法是切点
● 切点:service业务类中的所有业务方法
● 通知类:Spring提供的,通知方法已经定义好,只需要配置即可
分析:
● 通知类是Spring提供的,需要导入Spring事务的相关的坐标;
● 配置目标类AccountServiceImpl;
● 使用advisor标签配置切面。
配置目标类AccountServiceImpl
使用advisor标签配置切面
疑问:Spring提供的通知类是谁?是谁?是spring-tx包下的advice标签配置提供的
对上述配置进行详解一下
首先,平台事务管理器PlatformTransactionManager是Spring提供的封装事务具体操作的规范接口,封装了事务的提交和回滚方法
不同的持久层框架事务操作的方式有可能不同,所以不同的持久层框架有可能会有不同的平台事务管理器实现,例如,MyBatis作为持久层框架时,使用的平台事务管理器实现是DataSourceTransactionManager。Hibernate作为持久层框架时,使用的平台事务管理器是HibernateTransactionManager。
其次,事务定义信息配置,每个事务有很多特性,例如:隔离级别、只读状态、超时时间等,这些信息在开发时可以通过connection进行指定,而此处要通过配置文件进行配置
其中,name属性名称指定哪个方法要进行哪些事务的属性配置,此处需要区分的是切点表达式指定的方法与此处指定的方法的区别?切点表达式,是过滤哪些方法可以进行事务增强;事务属性信息的name,是指定哪个方法要进行哪些事务属性的配置
方法名在配置时,也可以使用 * 进行模糊匹配,例如:
isolation属性:指定事务的隔离级别,事务并发存在三大问题:脏读、不可重复读、幻读/虚读。可以通过设置事务的隔离级别来保证并发问题的出现,常用的是READ_COMMITTED 和 REPEATABLE_READ
isolation属性 | 解释 |
DEFAULT | 默认隔离级别,取决于当前数据库隔离级别,例如MySQL默认隔离级别是REPEATABLE_READ |
READ_UNCOMMITTED | A事务可以读取到B事务尚未提交的事务记录,不能解决任何并发问题,安全性最低,性能最高 |
READ_COMMITTED | A事务只能读取到其他事务已经提交的记录,不能读取到未提交的记录。可以解决脏读问题,但是不 |
REPEATABLE_READ | A事务多次从数据库读取某条记录结果一致,可以解决不可重复读,不可以解决幻读 |
SERIALIZABLE | 串行化,可以解决任何并发问题,安全性最高,但是性能最低 |
read-only属性:设置当前的只读状态,如果是查询则设置为true,可以提高查询性能,如果是更新(增删改)操作则设置为false
timeout属性:设置事务执行的超时时间,单位是秒,如果超过该时间限制但事务还没有完成,则自动回滚事务,不在继续执行。默认值是-1,即没有超时时间限制
propagation属性:设置事务的传播行为,主要解决是A方法调用B方法时,事务的传播方式问题的,例如:使用单方的事务,还是A和B都使用自己的事务等。事务的传播行为有如下七种属性值可配置
事务传播行为 | 解释 |
REQUIRED(默认值) | A调用B,B需要事务,如果A有事务B就加入A的事务中,如果A没有事务,B就自己创建一个事务 |
REQUIRED_NEW | A调用B,B需要新事务,如果A有事务就挂起,B自己创建一个新的事务 |
SUPPORTS | A调用B,B有无事务无所谓,A有事务就加入到A事务中,A无事务B就以非事务方式执行 |
NOT_SUPPORTS | A调用B,B以无事务方式执行,A如有事务则挂起 |
NEVER | A调用B,B以无事务方式执行,A如有事务则抛出异常 |
MANDATORY | A调用B,B要加入A的事务中,如果A无事务就抛出异常 |
NESTED | A调用B,B创建一个新事务,A有事务就作为嵌套事务存在,A没事务就以创建的新事务执行 |
xml方式声明式事务控制的原理浅析一下
<tx:advice>标签使用的命名空间处理器是TxNamespaceHandler,内部注册的是解析器是TxAdviceBeanDefinitionParser
TxAdviceBeanDefinitionParser中指定了要注册的BeanDefinition
TxAdviceBeanDefinitionParser二级父类AbstractBeanDefinitionParser的parse方法将TransactionInterceptor以配置的名称注册到了Spring容器中
TransactionInterceptor中的invoke方法会被执行,跟踪invoke方法,最终会看到事务的开启和提交
● 在AbstractPlatformTransactionManager的132行中开启的事务;
● 在TransactionAspectSupport的242行提交了事务。
- 基于注解声明式事务控制
注解就是对xml的替代
同样,使用的事务的注解,平台事务管理器仍然需要配置,还需要进行事务注解开关的开启
如果使用全注解的话,使用如下配置类的形式代替配置文件
来源:黑马程序员新版Spring零基础入门到精通,一套搞定spring全套视频教程(含实战源码)
相关文章:

吃透 Spring 系列—AOP部分
目录 ◆ AOP 简介 - AOP的概念 - AOP思想的实现方案 - 模拟AOP的基础代码 - AOP相关概念 ◆ 基于xml配置的AOP - xml方式AOP快速入门 - xml方式AOP配置详解 - xml方式AOP原理剖析 ◆ 基于注解配置的AOP - 注解方式AOP基本使用 - 注解方式AOP配置详解 - 注解…...
redis 问题解决 2
1.4 数据存储 1、Redis 的数据过期策略是什么? Redis的数据过期策略包括两种机制:被动删除和主动删除。 被动删除: 当某个键被访问时,如果发现这个键已经过期,Redis会立即删除这个键。这意味着如果一个过期的键从未被访问,它就不会被自动删除。这是一种惰性删除策略。主…...
Spring Boot 校验用户上传的图片文件
图片上传是现代应用中非常常见的一种功能,也是风险比较高的一个地方。恶意用户可能会上传一些病毒、木马。这些东西不仅严重威胁服务器的安全还浪费了带宽,磁盘等资源。所以,在图片上传的接口中,一定要对用户上传的文件进行严格的…...

【springboot配置项动态刷新】与【yaml文件转换为java对象】
文章目录 一,序言二,准备工作1. pom.xml引入组件2. 配置文件示例 三,自定义配置项动态刷新编码实现1. 定义自定义配置项对象2. 添加注解实现启动时自动注入3. 实现yml文件监听以及文件变化处理 四,yaml文件转换为java对象1. 无法使…...

JS移动端触屏事件
在我们PC端中有许多的事件,那我们在移动端有没有事件呢?让我为大家介绍一下移动端常用的事件,触屏事件 触屏事件 touch (也称触摸事件),Android 和IOS 都有 touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一…...

C语言——打印1000年到2000年之间的闰年
闰年: 1、能被4整除不能被100整除 2、能被400整除 #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int year;for(year 1000; year < 2000; year){if((year%4 0) && (year%100!0) || (year%400 0)){printf("%d ",ye…...
【Linux】【驱动】设备树下的paltform总线
【Linux】【驱动】设备树下的paltform总线 1. 驱动程序的完整代码2. 使用到的相关函数3 使用到的指令3.2 设备上使用的指令 1. 驱动程序的完整代码 主要是展示了通过总线上挂载的方式来实现相关的数据读取 实质上就是几个of函数的调用。 /** Author: topeet* Description: 设…...
洛谷 NOIP 2023 模拟赛-汪了个汪-题解
简要题意 棋盘上有 n n n 行,第 i i i 行有 i i i 个格子。你要在格子填 1 ∼ n 1\sim n 1∼n,满足: 每行第一个数互不相同所有在行上相邻的两个数所组成的无序对互不相同每行的数互不相同 n ≤ 4000 n\le4000 n≤4000 题解 容易发现…...
洛谷 NOIP 2023 模拟赛 P9836 种树
洛谷 NOIP 2023 模拟赛 P9836 种树 文章目录 洛谷 NOIP 2023 模拟赛 P9836 种树题目大意思路code 题目大意 路边有 n n n 棵树,每棵树的 高度 均为正整数,记作 p 1 , p 2 … p n p_1, p_2 \dots p_n p1,p2…pn。 定义一棵树的 宽度 为它高度的…...

链表经典OJ题(链表回文结构,链表带环,链表的深拷贝)
目录 前言 1.反转一个单链表。 2. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。 3.链表的回文结构。 4.链表带环问题(*****) 4.1是否带环 4.2 入环的节点 5.随机链表的复制(链表的深拷贝) 前言…...

AD教程 (十三)常见CHIP封装的创建
AD教程 (十三)常见CHIP(贴片)封装的创建 PCB封装是电子设计图纸和实物之间的映射体,具有精准数据的要求,在实际设计中需要通过规格书获取创建封装的数据参数。 PCB封装和实物的大小一致。PCB封装是承载实物…...

从0到1实现一个前端监控系统(附源码)
目录 一、从0开始 二、上报数据方法 三、上报时机 四、性能数据收集上报 收集上报FP 收集上报FCP 收集上报LCP 收集上报DOMContentLoaded 收集上报onload数据 收集上报资源加载时间 收集上报接口请求时间 五、错误数据收集上报 收集上报资源加载错误 收集上报js错…...
第7章-使用统计方法进行变量有效性测试-7.2-方差分析
目录 7.2 方差分析 7.2.1 单因素方差分析 组内变异 组间变异 总变异 随机误差...

【MongoDB】索引 – 文本索引(用权重控制搜索结果)
一、准备工作 这里准备一些数据 db.books.drop();db.books.insert({_id: 1, name: "Java", alias: "java 入门", description: "入门图书" }); db.books.insert({_id: 2, name: "C", alias: "c", description: "C 入…...

Git 入门使用
一、Git 入门 1.1 Git简介 Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。Git是由Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。 Git是目前世界上最先进的分布式版本控制系统,没有之一&a…...

如何写好接口自动化测试脚本
谈到接口测试,大家关注更多的是哪个工具更优秀,更好用。但是很少人关注到接口测试用例的设计问题,也很少人会去写接口用例,都代码化了嘛,还写什么用例,是吧? 这样真的对么?我们是不…...

openEuler编译安装nmon性能监控工具及可视化分析工具
ln 介绍 nmon(short for Nigel’s Monitor)是一个性能分析工具,由蓝色巨人IBM开发,最早用于自家操作系统UNIX,AIX (Advanced Interactive eXecutive)。现在也能用在Linux上。它可以显示系统的…...

96 前缀树Trie
前缀树 题解1 STL题解2 参考官方 Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。 请你实现 Trie 类: …...

“第六十六天”
这个我记得是有更优解的,不过还是明天发吧,明天想一想,看看能不能想起来 #include<string.h> int main() {char a[201] { 0 };char b[201] { 0 };scanf("%s %s", a, b);int na strlen(a);int nb strlen(b);int i 0, j …...

MYSQL5.7和MYSQL8配置主从
1、创建专门主从的账号 #登录 mysql -u root -p #创建用户 我这里用户名为test5,注意这里的ip是从库服务器的ip CREATE USER test5192.168.1.20 IDENTIFIED WITH mysql_native_password BY xxxxx; #给主从复制账号授权 grant replication slave on *.* to test5192…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...