Spring AOP + RabbitMq实现日志记录
一. AOP是什么?
AOP的编程思想就是把业务逻辑和横切的问题进行分离,从而达到解耦的目的,使代码的重用性和开发效率高(目的是重用代码,把公共的代码抽取出来)
二. AOP的应用场景
1、日志记录(以下演示)
2、权限验证
3、效率检查
4、事务管理(spring 的事务就是用AOP实现的)
三. AOP 概念说明
① 切面(Aspect):指的就是通用功能的代码实现,日志切面(代码如下),它们都是普通的Java类:OperationLogAspect,可以简单地认为, 使用 @Aspect 注解的类就是切面
@Component
@Aspect
public class OperationLogAspect {
}
② 目标对象(Target):目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。
③ 连接点(Join point ):连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法
@Before("pointcut()")
public void OperationLogPointCut(JoinPoint joinPoint) { //这个JoinPoint参数就是连接点
}
④ 切入点(Pointcut):定义通知应该切入到什么地方,Spring支持的切入点就是方法调用,切入点的定义可以使用正则表达式,用以描述什么类型的方法调用。@Pointcut就是用来定义切入点的
@Pointcut("execution(* com.demo.common.aop.service..*(..))")
public void pointcut() {
}
⑤ 通知(Advice):切面是一个类,而通知就是类里的方法以及这个方法如何织入到目标方法的方式(用@AfterReturning和@Around标注的方法)。根据织入到目标方法方式的不同,一共可以分为5种:
前置通知(Before)
后置通知(AfterReturning)
异常通知(AfterThrowing)
最终通知(After)
环绕通知(Around)
⑥ 织入(Weaving):AOP实现的过程,即将切面应用到目标对象,从而创建一个新的代理对象的过程,织入可以在编译时,类加载时和运行时完成。对于Spring来说,就是初始化Context中的对象时,完成织入操作。
四. RabbitMQ 集成Spring Boot 2.4
-
日志记录使用的消息模型为(Topics 通配符模式(交换机类型:topics))
-
每个消费者监听自己的队列,并且设置带通配符的routingkey,生产者将消息发给broker,由交换机根据routingkey来转发消息到指定的队列。
Routingkey一般都是有一个或者多个单词组成,多个单词之间以“.”分割,例如:log.topic.exchange
通配符规则:
#:匹配一个或多个词
*:匹配不多不少恰好1个词
-
RabbitMQ + SpringAOP 日志记录代码(部分)
RabbitMq 配置类
@Configuration
public class TopicMQConfig {
// 配置操作日志队列
public final static String OPERATE_LOG_QUEUE_NAME = "operate.log.queue";
// 路由的交换机
public final static String TOPIC_EXCHANGE_NAME = "log.topic.exchange";
// 配置操作日志TOPIC,#可以匹配多个
public final static String OPERATE_LOG_TOPIC = "topic.operateLog.#";
/**
* @Title: topicExchange
* @Description: 配置 TopicExchange Topic类型的交换机
*/
@Bean
public TopicExchange topicExchange() {
return new TopicExchange(TOPIC_EXCHANGE_NAME);
}
/**
* @Title: operateLogQueue
* @Description: 配置 operateLogQueue 操作日志队列
*/
@Bean
public Queue operateLogQueue() {
return new Queue(OPERATE_LOG_QUEUE_NAME);
}
/**
* @Title: operateLogBinding
* @Description: 将操作日志队列绑定到TOPIC_EXCHANGE_NAME交换机,并且匹配规则为匹配多个
*/
@Bean
public Binding operateLogBinding() {
return BindingBuilder.bind(operateLogQueue()).to(topicExchange()).with(OPERATE_LOG_TOPIC);
}
}
生产者部分:
// 发消息队列
rabbitTemplate.convertAndSend(TopicMQConfig.TOPIC_EXCHANGE_NAME,"topic.operateLog.operate",sysOperationLog);
消费者部分:
@RabbitListener(queues = {TopicMQConfig.OPERATE_LOG_QUEUE_NAME},
containerFactory = "rabbitListenerContainerFactory")
@RabbitHandler
public void insertLog(SysOperationLog sysOperationLog){
if (sysOperationLog != null){
sysOperationLogService.saveOperationLog(sysOperationLog);
log.info("接收到消息:{}",sysOperationLog);
}
}