SpringBoot2⾃定义注解,以AOP简单⽇志记录为例
⽂章⽬录
⼀、前⾔
好久不见,⼤家还好吗?
最近开始学习框架:⼀个基于SpringBoot的后台管理系统,作为快速开发框架,⽹上评价不错,有时间的同学可以看看代码学习⼀下。
⼀开始打算以若依框架中关于Controller层的Log注解作为模板进⾏⾃定义注解的介绍,因为在切⾯类中涉及到了⼀些基础框架层的封装类及⽅法,如果深⼊去讲摊⼦会铺的很⼤,就脱离了⾃定义注解的主题,因此本⽂仅仅以最简单的程序来演⽰⼀下SpringBoot⾃定义注解的实现。仅做演⽰
⼆、正⽂开始
1、项⽬结构:最简单的SpringBoot脚⼿架搭建的web项⽬
pom依赖:
<dependencies>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
server:
port:12345
2、⾃定义注解
package;
import*;
/**
* @Author: zongshaofeng
* @Description: ⾃定义的操作⽇志注解
* @Date:Create:in 2021/10/22 8:25
* @Modified By:
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interface OperationLog {
/**
* 模块名称
*/
String title()default"";
/**
* 为了简单,省略后续内容
*/
}
3.⾃定义注解切⾯类
package;
import OperationLog; import JoinPoint;
import ProceedingJoinPoint;
import*;
import Component;
import HashMap;
import Map;
/**
* @Author: zongshaofeng
* @Description: 操作⽇志记录的切⾯类
* @Date:Create:in 2021/10/22 8:30
* @Modified By:
* @Modified By:
*/
@Aspect
@Component
public class OperationLogAspect {
/**
* @Author: zongshaofeng
* @Description: 返回增强,⽬标⽅法正常执⾏完毕时执⾏
* @Date: 2021/10/22 20:15
* @param: joinPoint
* @param: operationLog
* @param: returnObj
* @return: void
* @Version: 1.0
*/
@AfterReturning(pointcut ="@annotation(operationLog)",returning ="returnObj")
public void doAfterReturning(JoinPoint joinPoint, OperationLog operationLog, Object returnObj){
System.out.println("===============AfterReturning切⼊点开始执⾏......===============");
Map<String,Object> map=new HashMap<>();
map.put("title",operationLog.title());
map.put("returnObj",returnObj);
map.put("method",Target().getClass().getName()+"."+Signature().getName());  System.out.println(map);
System.out.println("===============AfterReturning切⼊点执⾏完成。===============");
}
/**
* @Author: zongshaofeng
* @Description: 异常抛出增强,⽬标⽅法发⽣异常的时候执⾏
* @Date: 2021/10/22 20:16
* @param: joinPoint
* @param: operationLog
* @param: e
* @return: void
* @Version: 1.0
*/
@AfterThrowing(pointcut ="@annotation(operationLog)",throwing ="e")
public void doAfterThrowing(JoinPoint joinPoint, OperationLog operationLog, Exception e){
System.out.println("===============AfterThrowing切⼊点开始执⾏......===============");
Map<String,Object> map=new HashMap<>();
map.put("title",operationLog.title());
map.put("exceptionMsg",e.getMessage());
map.put("method",Target().getClass().getName()+"."+Signature().getName());  System.out.println(map);
System.out.println("===============AfterThrowing切⼊点执⾏完成。===============");
}
/**
* @Author: zongshaofeng
* @Description: 前置增强:在⽬标⽅法执⾏之前
* @Date: 2021/10/22 20:16
* @param: joinPoint
* @param: operationLog
* @return: void
* @Version: 1.0
*/
@Before(value ="@annotation(operationLog)")
public void doBefore(JoinPoint joinPoint, OperationLog operationLog){
System.out.println("===============Before切⼊点开始执⾏......===============");
Map<String,Object> map=new HashMap<>();
map.put("title",operationLog.title());
map.put("method",Target().getClass().getName()+"."+Signature().getName());  System.out.println(map);
System.out.println("===============Before切⼊点执⾏完成。===============");
}
/**
* @Author: zongshaofeng
* @Description: 后置增强,不管是抛出异常或者正常退出都会执⾏
* @Date: 2021/10/22 20:17
* @Date: 2021/10/22 20:17
* @param: joinPoint
* @param: operationLog
* @return: void
* @Version: 1.0
*/
@After(value ="@annotation(operationLog)")
public void doAfter(JoinPoint joinPoint, OperationLog operationLog){
System.out.println("===============After切⼊点开始执⾏......===============");
Map<String,Object> map=new HashMap<>();
map.put("title",operationLog.title());
map.put("method",Target().getClass().getName()+"."+Signature().getName());
System.out.println(map);
System.out.println("===============After切⼊点执⾏完成。===============");
}
/**
* @Author: zongshaofeng
* @Description:环绕通知:⽬标⽅法执⾏前后进⾏⼀些操作
* @Date: 2021/10/22 20:17
* @param: proceedingJoinPoint
* @param: operationLog
* @return: java.lang.Object
* @Version: 1.0
*/
@Around(value ="@annotation(operationLog)")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint, OperationLog operationLog)throws Throwable {
System.out.println("===============Around切⼊点开始执⾏......===============");
Map<String,Object> map=new HashMap<>();
map.put("title",operationLog.title());
map.put("method",Target().getClass().getName()+"."+Signature().getName());  System.out.println(map);
spring aop应用场景System.out.println("---------Around中前置通知执⾏完成-------");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("---------Around中⽬标⽅法返回结果:"+proceed);
System.out.println("---------Around中⽬标⽅法执⾏完成-------");
System.out.println("这是后置通知。。。");
System.out.println("---------Around中后置通知执⾏完成-------");
System.out.println("===============Around切⼊点执⾏完成。===============");
return proceed;
}
}
4、Controller层
package;
import OperationLog;
import GetMapping;
import Mapping;
import RequestMapping;
import RestController;
/**
* @Author: zongshaofeng
* @Description:
* @Date:Create:in 2021/10/22 8:16
* @Modified By:
*/
@RestController
@RequestMapping("/demo")
public class SayHelloController {
@GetMapping("/sayHello")
@OperationLog(title ="⾃定义⽇志注解测试-说你好模块")
public String sayHello(String name){
return"Hello "+ name;
}
}
5、基本概念简述
AOP(Aspect Oriented Programming,⾯向切⾯编程)是通过预编译⽅式和运⾏期动态代理实现程序功能的统⼀维护的⼀种技术。AOP是OOP的延续,是软件开发中的⼀个热点,也是Spring框架中的⼀个重要内容,是函数式编程的⼀种衍⽣范型。利⽤AOP 可以对业务逻辑的各个部分进⾏隔离,从⽽使得业务逻辑各部分之间的耦合度降低,提⾼程序的可重⽤性,同时提⾼了开发的效率。
在Spring AOP中业务逻辑仅仅只关注业务本⾝,将⽇志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,从⽽在改变这些⾏为的时候不影响业务逻辑的代码。
AOP 涉及的相关注解主要有以下⼏个:
注解作⽤
@Aspect定义切⾯类
@Pointcut
Pointcut是织⼊Advice的触发条件。每个Pointcut的定义包括2部分,⼀是表达式,⼆是⽅法签名。⽅法签名必须是public及void 型。可以将Pointcut中的⽅法看作是⼀个被Advice引⽤的助记符,因为表达式不直观,因此我们可以通过⽅法签名的⽅式为此表达式命名。因此Pointcut中的⽅法只需要⽅法签名,⽽不需要在⽅法体内编写实际代码。
@Around环绕通知:⽬标⽅法执⾏前后进⾏⼀些操作
@Before前置增强:在⽬标⽅法执⾏之前
@AfterReturning返回增强,⽬标⽅法正常执⾏完毕时执⾏
@AfterThrowing异常抛出增强,⽬标⽅法发⽣异常的时候执⾏
@After后置增强,不管是抛出异常或者正常退出都会执⾏
三、看运⾏结果,说结论
⽂字看起来记不住,让我们运⾏⼀下,看看这⼏个增强通知的执⾏顺序是怎样的,这样在今后的实际开发中才能够得⼼应⼿,运⽤⾃如。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。