一、简介
Spring AOP 提供全面的 AOP 解决方案。Spring 将 Spring AOP 和 IOC 与 AspectJ 无缝集成,以便在一致的 Spring-based application architecture 中满足 AOP 的所有使用需求。
二、SpringBoot集成Spring-Aop
添加依赖
maven依赖添加如下
<!--引入SpringBoot的Web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注意:在完成了引入AOP依赖包后,不需要去做其他配置。AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy,不需要在程序主类中增加@EnableAspectJAutoProxy来启用。
编写切面代码
切面类使用@Aspect标注,必须加 @Component,使得切面类注入IOC容器管理
@Aspect
@Component
@Slf4j
public class TestLog {
@Pointcut("execution(* com.yuntian.example.controller.*.*(..))")
public void testLog() {
}
/**
* 前置通知,方法执行之前执行
* @param jp
*/
@Before("testLog()")
public void doBefore(JoinPoint jp) {
// ...
log.info("方法执行前:.............");
}
/**
* 后置通知,方法执行之后执行(不管是否发生异常)
* @param jp
*/
@After("testLog()")
public void doAfter(JoinPoint jp) {
// ...
log.info("方法执行后:.............");
}
/**
* 返回通知,方法正常执行完毕之后执行
* @param jp
*/
@AfterReturning("testLog()")
public void doAfterReturning(JoinPoint jp) {
// ...
log.info("方法执行后返回通知:.............");
}
/**
* 异常通知,在方法抛出异常之后执行
* @param jp
* @param e
*/
@AfterThrowing(value="testLog()",throwing="e")
public void doAfterThrowing(JoinPoint jp,Exception e) {
// ...
log.info("方法执行后异常:.............");
}
}
业务代码
package com.yuntian.example.controller;
import com.yuntian.example.base.Result;
import com.yuntian.example.entity.dto.OrderDTO;
import com.yuntian.example.entity.vo.OrderVO;
import com.yuntian.example.service.OrderService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author yuntian.
* @date Created in 18:13 2019/8/7
* @description
*/
@RestController
@RequestMapping("order")
public class OrderController {
@Resource
private OrderService orderService;
@PostMapping("/createOrder")
public Result createOrder(OrderDTO dto){
OrderVO orderVO= orderService.createOrder(dto);
Result<OrderVO> result=new Result<>();
result.setData(orderVO);
result.setCode(99);
return result;
}
}
结果
可以看到切面类,实现逻辑同时,而对业务代码毫无侵入。
编写切面代码,使用环绕通知
@Aspect
@Component
@Slf4j
public class TestLogAround {
@Pointcut("execution(* com.yuntian.example.controller.*.*(..))")
public void testLogAround() {
}
/**
* 使用环绕通知
* @param pjp
* @return
*/
@Around("testLogAround()")
public Object doAround(ProceedingJoinPoint pjp){
Object obj=null;
try{
log.info("前置通知:执行之前");
obj=pjp.proceed();
log.info("返回通知:执行之后");
} catch(Throwable e){
log.info("异常通知:........!");
}
return obj;
}
}
结果
编写切面代码,配合自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MTransaction {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
int timeout() default -1;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
@Component
@Slf4j
@Aspect
public class TransactionAspect {
@Pointcut("@annotation(com.yuntian.example.annotation.MTransaction)")
public void transactionAspect() {
}
/**
* 使用环绕通知
*
* @param pjp
* @return
*/
@Around("transactionAspect()")
public Object doAround(ProceedingJoinPoint pjp) {
//获得执行方法的类名
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
Object[] args= pjp.getArgs();
Object obj = null;
try {
log.info("前置通知:开启事务...");
MTransaction transaction = method.getAnnotation(MTransaction.class);
if (transaction != null) {
log.info("注解信息:" + transaction.value());
}
log.info("参数:"+JSON.toJSONString(args));
obj = pjp.proceed();
log.info("返回通知:关闭事务...");
} catch (Throwable e) {
log.info("异常通知:事务回滚...");
}
return obj;
}
}
结果
二、切面介绍
切点表达式
切入点是范围内的所有类的方法
@Pointcut("execution(* com.yuntian.example.controller.*.*(..))")
切入点是注解的方法
@Pointcut("@annotation(com.yuntian.example.annotation.MTransaction)")
AspectJ指示器
指示器 | 描述 |
---|---|
arg() | 限制连接点匹配参数为指定类型的执行方法 |
@args() | 限制连接点匹配参数为指定注解标注的执行方法 |
execution() | 用于匹配是连接点的执行方法 |
this() | 限制连接点匹配参数为指定注解标注的执行方法 |
target | 限制连接点匹配目标对象为指定类型的类 |
within() | 限制连接点匹配指定的类型 |
@within() | 限制连接点匹配指定注解锁标注的类型(当使用Spring Aop时,方法定义由指定的注解所标注的类) |
@annotation | 限制匹配带有指定注解的连接点 |