Spring AOP 提供全面的 AOP 解决方案。Spring 将 Spring AOP 和 IOC 与 AspectJ 无缝集成,以便在一致的 Spring-based application architecture 中满足 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)") 复制代码