引言
在之前做的项目中,突然冒出来一个从未提及的需求(这是很常见的情况),原因是商家要经常做打折活动,这就意味着要在每种类型的订单接口中添加代码进行计算,或者就是在POJO类中添加字段。我果断选择了使用AOP来解决。本片文章为大家介绍AOP以及AOP的使用。
Spring AOP
面向切面的编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象的编程(OOP)。OOP中模块化的关键单位是类,而AOP中模块化的单位是切面。切面使跨越多种类型和对象的关注点(如事务管理)模块化。常被应用于事务处理、日志管理、权限控制、异常处理等。
简单的说,就是在不修改源代码的前提下,为系统中的业务添加特定功能。
AOP概念
Aspect(切面): 一个跨越多个类的关注点的模块化。事务管理是企业级Java应用中横切关注点的一个很好的例子。在Spring AOP中,切面是通过使用常规类(基于 schema 的方法)或使用
@Aspect
注解的常规类(@AspectJ 风格)实现的。Join point: 程序执行过程中的一个点,俗称连接点。在Spring AOP中,一个连接点总是代表一个方法的执行。
Advice: 指的是拦截后要做的事情,切入点增强的内容。
Pointcut: 切入点,意思是要对哪些方法进行拦截或者添加功能。
Target object: 指代理的目标对象。
AOP proxy: 一个由AOP框架创建的对象,以实现切面契约(advice 方法执行等)。在Spring框架中,AOP代理是一个JDK动态代理或CGLIB代理。
Weaving(织入): 将aspect与其他应用程序类型或对象连接起来,以创建一个 advice 对象。
AOP提供的advice
Before advice: 在连接点之前运行的Advice ,但它不具备以下能力 阻止执行流进行到 join point 的能力(除非它抛出一个异常)。
After returning advice: 在一个连接点正常完成后运行的Advice (例如,如果一个方法返回时没有抛出一个异常)。
After (finally) advice: 无论连接点以何种方式退出(正常或特殊返回),都要运行该advice。
Around advice: 围绕一个连接点的advice,如方法调用。这是最强大的一种advice。Around advice可以在方法调用之前和之后执行自定义行为。它还负责选择是否继续进行连接点或通过返回自己的返回值或抛出一个异常来缩短advice方法的执行。
编写AOP
AOP编写很简单,大致分为三步。需求:MQ中存在 ”123456“:“川菜“:”20“ 的数据消费者消费消息的时候发现该条数据记录的商品要进行打折吗,在不修改源代码的情况下,修改为”123456“:“川菜“:”15“ 。
导入AOP相关依赖
<!--aop依赖1:aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.5</version>
</dependency>
<!--aop依赖2: aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
如果使用的是SpringBoot则不需要引入,会自动装配。
定义切面,简单来说就是挑选要增强的业务模块。
这里我选择消费者的模块。
2.定义切入点,就是在要增强的业务模块中挑选接口或者方法。
在这里我选择对MqListener中的所有方法进行加强,同时定义切入点。
package cn.cxj.mq.listeners;
import cn.cxj.mq.pojo.order;
import cn.cxj.mq.service.orderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class MqListener {
@Autowired
private orderService orderService;
//声明队列 mq的容器工厂
// @RabbitListener(bindings = @QueueBinding(value = @Queue(name="demo.queue"),exchange = @Exchange(name = "direct",type = ExchangeTypes.DIRECT),key = {"粤菜"}) ,containerFactory = "customContainerFactory")
@Async("pooltoconsumer")
@RabbitListener(bindings = @QueueBinding(value = @Queue(name="demo.queue"),exchange = @Exchange(name = "direct",type = ExchangeTypes.DIRECT),key = {"粤菜"}) )
public void yuecai(String msg)
{
//拆分消息
System.out.println(msg);
String[] split = msg.split(":");
order order = new order(split[0], split[1],Integer.valueOf(split[2]));
System.out.println(order.toString());
//保存MYSQL
orderService.save(order);
//测试是否多个消费者
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务" +"-------------"+"粤菜"+"----"+split[1]);
}
// @RabbitListener(bindings = @QueueBinding(value = @Queue(name="demo.queue2"),exchange = @Exchange(name = "direct",type = ExchangeTypes.DIRECT),key = {"川菜"}) ,containerFactory = "customContainerFactory")
@Async("pooltoconsumer")
@RabbitListener(bindings = @QueueBinding(value = @Queue(name="demo.queue2"),exchange = @Exchange(name = "direct",type = ExchangeTypes.DIRECT),key = {"川菜"}) )
public void chuancai(String msg)
{
System.out.println("111111"+msg);
//拆分消息
String[] split = msg.split(":");
order order = new order(split[0], split[1],Integer.valueOf(split[2]));
System.out.println(order.toString());
//保存MYSQL
orderService.save(order);
//测试是否多个消费者
System.out.println("线程" + Thread.currentThread().getName() + " 执行异步任务" +"----"+"川菜"+"----"+split[1]);
}
}
@Pointcut("execution(* cn.itcast.mq.controller.Test.*(..))")
public void log(){
}
3.定义AOP通知进行增强处理。
@Around("log()")
public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
args[0]="123456:川菜:15";
log.info("method {} start"+joinPoint.getSignature().getName());
return joinPoint.proceed(args);
}
运行服务,查看结果,数据修改成功!
总结
通过本篇文章的学习,相信大家对AOP的基本概念和基本使用有了深刻的印象。AOP提高了代码的可拓展性,是Spring中重要的一种思想,希望大家可以灵活运用!