编辑
2023-12-06
学习记录
00

前提

AOP,全称是Aspect Oriented Programming,即面向切面编程。AOP的目的是将那些与业务无关,但是业务模块都需要的功能,如日志统计、安全控制、事务处理等,封装成可重用的组件,从而将它们从业务逻辑代码中划分出来,编写成独立的切面。这样做,既可以保持业务逻辑的纯净和高内聚性,又可以使得系统的多个模块都可以共享这些公共的功能。 Spring框架提供了对AOP的支持,Spring Boot自然也不例外。使用Spring Boot的AOP功能,我们可以在运行时动态地将代码横向切入到各个关注点(方法或者类)中。这种横向切面的方式,比传统的纵向切面(继承)更加灵活。

依赖

xml

java
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency>
编辑
2023-12-05
学习记录
00

前提

redis是我们经常使用的一个中间件,他是内存数据库,使用中经常会存一些list或者其他数据结构,内容很多的话,就会产生大key

导致问题

  1. 内存占用过高:大Key会占用大量的内存空间,可能导致可用内存不足,从而触发内存淘汰策略。在极端情况下,可能导致内存耗尽,Redis实例崩溃,影响系统的稳定性。
  2. 性能下降:大Key会占用大量内存空间,导致内存碎片增加,进而影响Redis的性能。对于大Key的操作,如读取、写入、删除等,都会消耗更多的CPU时间和内存资源,进一步降低系统性能。
  3. 阻塞其他操作:某些对大Key的操作可能会导致Redis实例阻塞。例如,使用DEL命令删除一个大Key时,可能会导致Redis实例在一段时间内无法响应其他客户端请求,从而影响系统的响应时间和吞吐量。
  4. 网络拥塞:每次获取大key产生的网络流量较大,可能造成机器或局域网的带宽被打满,同时波及其他服务。例如:一个大key占用空间是1MB,每秒访问1000次,就有1000MB的流量。
  5. 主从同步延迟:当Redis实例配置了主从同步时,大Key可能导致主从同步延迟。由于大Key占用较多内存,同步过程中需要传输大量数据,这会导致主从之间的网络传输延迟增加,进而影响数据一致性。
  6. 数据倾斜:在Redis集群模式中,某个数据分片的内存使用率远超其他数据分片,无法使数据分片的内存资源达到均衡。另外也可能造成Redis内存达到maxmemory参数定义的上限导致重要的key被逐出,甚至引发内存溢出。

解决方式

  1. 压缩 适用于字符串类型的 redis key。采用压缩算法,将 key 压缩至可接受的范围内。压缩也是有讲究的,首先要选择无损的压缩算法,然后在压缩速率和压缩率之间也要权衡。比较常用的压缩算法/工具如下:

google snappy:无损压缩,追求压缩速度而不是压缩率(Compression rate) message pack:无损压缩,仅适用于 json 字符串的压缩,可以得到一个更小的 JSON,官网是:msgpack.org

  1. 分割 适用于 list,set,hash 等容器类型的 redis key。规范要求容器的元素数量 < 5000,我们可以在写 redis 的时候做个逻辑,如果超过了 5000 的容器就做切片。

  2. 抛弃 redis不存储过大的,可以直接查询数据库,或者是将不太重要的数据存储再Mongodb中,直接从mongodb查询

编辑
2023-12-05
学习记录
00

前提

在项目中有很多情况下需要使用多线程的方式执行任务,那么有什么比较好的方法来判断多线程任务执行完毕,我们再进行下一步的操作,之前的话我会设置等待时间来等待

java
executor.awaitTermination(30, TimeUnit.MINUTES);

方案

  • 使用 getCompletedTaskCount() 统计出【已完成任务数】和使用Java线程池中的getTaskCount() 方法来获取【总任务数】,二者进行对比即可。
  • 使用 FutureTask对象 ,等待所有任务都执行完,线程池的任务就都执行完了。
  • 使用 CountDownLatch对象 或 CyclicBarrier对象,等待所有线程都执行完之后,再执行后续流程,计数。
  • 使用isTerminated() 方法。利用线程池的终止状态(TERMINATED)来判断线程池的任务是否已经全部执行完,但想要线程池的状态发生改变,就需要调用线程池的 shutdown() 方法,不然线程池一直会处于 RUNNING 运行状态,那就没办法使用终止状态来判断任务是否已经全部执行完了,shutdown() 方法是启动线程池有序关闭的方法,它在完全关闭之前会执行完之前所有已经提交的任务,并且不会再接受任何新任务。当线程池中的所有任务都执行完之后,线程池就进入了终止状态,调用 isTerminated() 方法返回的结果就是 true 了,以这点作为依据来判断即可。
编辑
2023-12-05
遇到的问题
00

前提

在使用mongodb排序的时候需要构建一个sort对象,传入query.with()方法中,实现排序功能,但是直接new对象会提示

'Sort(org.springframework.data.domain.Sort.Direction, java.util.List<java.lang.String>)' has private access in 'org.springframework.data.domain.Sort'

因为springboot2.2.1(含)以上的版本Sort已经不能再实例化了,构造方法已经是私有的了!

可以改用Sort.by获得Sort对象。

解决方法

使用Sort s=Sort.by()方法创建对象by方法的底层:

java
public static Sort by(List<Sort.Order> orders) { Assert.notNull(orders, "Orders must not be null!"); return orders.isEmpty() ? unsorted() : new Sort(orders); }
编辑
2023-12-04
学习记录
00

验证码依赖

xml
<!-- 验证码 --> <dependency> <groupId>pro.fessional</groupId> <artifactId>kaptcha</artifactId> <version>2.3.3</version> </dependency>
  • kaptcha 是一个很有用的验证码生成工具。有了它,你能够生成各种样式的验证码,由于它是可配置的。
  • kaptcha工作的原理是调用com.google.code.kaptcha.servlet.KaptchaServlet,生成一个图片。
  • 同一时候将生成的验证码字符串放到 HttpSession中。
  • 使用kaptcha可以方便的配置: 验证码的字体 验证码字体的大小 验证码字体的字体颜色 验证码内容的范围(数字,字母,中文汉字!) 验证码图片的大小,边框,边框粗细,边框颜色 验证码的干扰线(可以自己继承com.google.code.kaptcha.NoiseProducer写一个自定义的干扰线) 验证码的样式(鱼眼样式、3D、普通模糊……当然也可以继承com.google.code.kaptcha.GimpyEngine自定义样式)

装载验证码启用状态到Redis

这是个方法是在项目初始化执行的,在ruoyi-system模块下的SysConfigServiceImpl中,作者给方法加上了@PostConstruct注解,这个注解的目的是在这个类初始化完成后就会执行这个方法,方法的内容是从sys_confg表中找到基础配置信息,循环的存在redis中