SpringBoot學習之整合AOP
點擊上方藍色字體,選擇“標星公眾號”
優(yōu)質文章,第一時間送達
基于SpringBoot整合Aop記錄日志
SpringBoot各版本參考文檔
https://docs.spring.io/spring-boot/docs/
查找引入依賴

引入依賴
??
????org.springframework.boot
????spring-boot-starter-aop
??切面類
??package?link.lycreate.springbooteasyexceldemo.aspect;
??import?lombok.extern.slf4j.Slf4j;
??import?org.aspectj.lang.JoinPoint;
??import?org.aspectj.lang.ProceedingJoinPoint;
??import?org.aspectj.lang.annotation.*;
??import?org.aspectj.lang.reflect.MethodSignature;
??import?org.springframework.stereotype.Component;
??import?org.springframework.web.context.request.RequestAttributes;
??import?org.springframework.web.context.request.RequestContextHolder;
??import?org.springframework.web.context.request.ServletRequestAttributes;
??import?javax.servlet.http.HttpServletRequest;
??import?java.lang.reflect.Method;
??import?java.util.Arrays;
??/**
??*?@ClassName?LogAspect
??*?@Description?TODO?日志切面類$
??*?@Author?charlesYan
??*?@Date?2020/10/9?12:53
??*?@Version?1.0
??**/
??@Aspect??//?聲明是一個切面組件
??@Component?//?加入到IOC容器
??@Slf4j??//?等同于?private?final?Logger?logger?=?LoggerFactory.getLogger(XXX.class);
??public?class?LogAspect?{
??????/**
??????*?@Author?charlesYan
??????*?@Description?//?指定切入點表達式,攔截那些方法,即為哪些類生成代理對象
??????*??????第一*表示匹配任何返回值的方法
??????*??????第二*表示匹配controller包下的所有類
??????*??????第三*表示匹配類下的所有方法
??????*??????..表示任何個數參數,和如何類型的參數
??????**/
??????//@Pointcut("execution(*?link.lycreate.springbooteasyexceldemo.controller.*.*(..))")
??????@Pointcut("@annotation(link.lycreate.springbooteasyexceldemo.aspect.LogFilter)")?//在所有標記指定注解的方法上攔截
??????public?void?logPointCut(){}
??????/**
??????*?@Author?charlesYan
??????*?@Description //前置通知:在目標方法執(zhí)行前調用
??????**/
??????@Before("logPointCut()")
??????public?void?before(JoinPoint?joinPoint){
??????????System.out.println("---------------Before?Begin?CurrentTime?=?"?+?System.currentTimeMillis());
??????????/*獲取當前請求的HttpServletRequest*/
??????????RequestAttributes?requestAttributes?=?RequestContextHolder.getRequestAttributes();
??????????HttpServletRequest?request?=?((ServletRequestAttributes)requestAttributes).getRequest();
??????????log.info("URL-->"+request.getRequestURL().toString());
??????????log.info("IP-->"+request.getRemoteAddr());
??????????log.info("HTTP_Method-->"+request.getMethod());
??????????log.info("Request_args-->"+?Arrays.toString(joinPoint.getArgs()));
??????????System.out.println("---------------Before?End?CurrentTime?=?"?+?System.currentTimeMillis());
??????}
??????/**
??????*?@Author?charlesYan
??????*?@Description?//返回通知?在目標方法執(zhí)行后調用,若目標方法出現異常,則不執(zhí)行
??????**/
??????@AfterReturning(value?=?"logPointCut()",returning?=?"obj")
??????public?void?afterReturning(JoinPoint?joinPoint,Object?obj){
??????????System.out.println("---------------AfterReturn?CurrentTime?=?"?+?System.currentTimeMillis());
??????}
??????/**
??????*?@Author?charlesYan
??????*?@Description //后置通知:無論目標方法在執(zhí)行過程中是否出現異常都會在它之后調用
??????**/
??????@After("logPointCut()")
??????public?void?after(JoinPoint?joinPoint){
??????????System.out.println("---------------After?CurrentTime?=?"?+?System.currentTimeMillis());
??????}
??????/**
??????*?@Author?charlesYan
??????*?@Description //異常通知:目標方法拋出異常時執(zhí)行
??????**/
??????@AfterThrowing(value?=?"logPointCut()",?throwing?=?"ex")
??????public?void?afterThrowing(JoinPoint?joinPoint,Exception?ex){
??????????System.out.println("---------------AfterThrowing?CurrentTime?=?"?+?System.currentTimeMillis());
??????}
??????/**
??????*?@Author?charlesYan
??????*?@Description //環(huán)繞通知:是前面四個通知的結合體
??????*?????????需要在方法之前執(zhí)行,可以寫在joinPoint.procedd();之前
??????*?????????需要在方法之后執(zhí)行,可以寫在joinPoint.procedd();之后
??????**/
??????@Around("logPointCut()")
??????public?void?around(ProceedingJoinPoint?joinPoint)?throws?Throwable?{
??????????//?獲取目標方法的名稱
??????????String?methodName?=?joinPoint.getSignature().getName();
??????????//?獲取方法傳入參數
??????????Object[]?params?=?joinPoint.getArgs();
??????????MethodSignature?signature?=?(MethodSignature)?joinPoint.getSignature();
??????????Method?method?=?signature.getMethod();
??????????//?獲取方法上LogFilter注解
??????????LogFilter?logFilter?=?method.getAnnotation(LogFilter.class);
??????????String?value?=?logFilter.value()?;
??????????log.info("模塊描述:"+value);
??????????System.out.println("---------------Around?Before?CurrentTime?=?"?+?System.currentTimeMillis()?+?" method name:"?+?methodName?+?" args:"?+?params[0]);
??????????//?執(zhí)行源方法
??????????joinPoint.proceed();
??????????System.out.println("---------------Around?After?CurrentTime?=?"?+?System.currentTimeMillis()?+?" method name:"?+?methodName?+?" args:"?+?params[0]);
??????}
??}自定義注解
??/**
??*?@ClassName?LogFilter
??*?@Description?TODO?自定義日志注解類$
??*?@Author?charlesYan
??*?@Date?2020/10/11?17:59
??*?@Version?1.0
??**/
??@Target(ElementType.METHOD)//Target注解決定LogFilter注解可以加在哪些成分上,如加在類身上,或者屬性身上,或者方法身上等成分
??@Retention(RetentionPolicy.RUNTIME)//Retention注解括號中的"RetentionPolicy.RUNTIME"意思是讓LogFilter這個注解的生命周期一直程序運行時都存在
??@Documented
??public?@interface?LogFilter?{
??????String?value()?default?"";
??}
請求方法
??@LogFilter("保存請求日志")
??@RequestMapping(path?=?"/saveRequestLog",method?=?RequestMethod.POST)
??public?String?saveRequestLog(@RequestParam("name")String?name){
??????return?"請求成功:"?+?name;
??}
測試方式

報錯信息
方法參數未聲明
報錯信息
??Caused?by:?java.lang.IllegalArgumentException:?error?at?::0?formal?unbound?in?pointcut截圖信息

錯誤代碼
??/**
??*?@Author?charlesYan
??*?@Description?//返回通知?在目標方法執(zhí)行后調用,若目標方法出現異常,則不執(zhí)行
??**/
??@AfterReturning("logPointCut()")
??public?void?afterReturning(JoinPoint?joinPoint,Object?obj){
??????System.out.println("---------------AfterReturn?CurrentTime?=?"?+?System.currentTimeMillis());
??}
正確代碼
??/**
??*?@Author?charlesYan
??*?@Description?//返回通知?在目標方法執(zhí)行后調用,若目標方法出現異常,則不執(zhí)行
??**/
??@AfterReturning(value?=?"logPointCut()",?returning?=?"obj")
??public?void?afterReturning(JoinPoint?joinPoint,Object?obj){
??????System.out.println("---------------AfterReturn?CurrentTime?=?"?+?System.currentTimeMillis());
??}
原因分析
??新增的方法參數未賦值
總結
Aop切面通知執(zhí)行順序
例圖

通知注解中的value屬性補充
自定義注解
??//注解實體類
??package?com.trip.demo;
??import?java.lang.annotation.ElementType;
??import?java.lang.annotation.Retention;
??import?java.lang.annotation.RetentionPolicy;
??import?java.lang.annotation.Target;
??@Retention(RetentionPolicy.RUNTIME)
??@Target({?ElementType.METHOD?})
??public?@interface?SMSAndMailSender?{
??????/*短信模板String格式化串*/
??????String?value()?default?"";
??????String?smsContent()?default?"";
??????String?mailContent()?default?"";
??????/*是否激活發(fā)送功能*/
??????boolean?isActive()?default?true;
??????/*主題*/
??????String?subject()?default?"";
??}
切面類中的切面方法
??/**
??*?在所有標記了@SMSAndMailSender的方法中切入
??*?@param?joinPoint
??*?@param?obj
??*/
??@AfterReturning(value="@annotation(com.trip.demo.SMSAndMailSender)",?returning="obj")
??public?void?afterReturning(JoinPoint?joinPoint,Object?obj){
??????System.out.println("---------------AfterReturn?CurrentTime?=?"?+?System.currentTimeMillis());
??}
參考鏈接
SpringBoot整合Aop
https://www.cnblogs.com/fernfei/p/12092510.html
SpringBoot整合aop
https://www.cnblogs.com/myitnews/p/11848159.html
SpringBoot 通過自定義注解實現AOP切面編程實例
https://www.cnblogs.com/lingyejun/p/9941350.html
SpringBoot2.0 基礎案例(11):配置AOP切面編程,解決日志記錄業(yè)務
https://my.oschina.net/cicadasmile/blog/3073069
淺談Spring AOP 面向切面編程 最通俗易懂的畫圖理解AOP、AOP通知執(zhí)行順序~
https://www.cnblogs.com/ChromeT/p/11823735.html
@interface 注解詳解
https://blog.csdn.net/u010882691/article/details/82427520
版權聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/weixin_42586723/article/details/109017827


??? ?
感謝點贊支持下哈?
