SpringBoot@Aspect 打印訪問(wèn)請(qǐng)求和返回?cái)?shù)據(jù)方式
SpringBoot@Aspect 打印訪問(wèn)請(qǐng)求和返回?cái)?shù)據(jù)
為什么要用aspect, 使用aspect 可以使記錄日志的功能面向切面,這樣可以降低代碼的耦合性。提供了兩種方式對(duì)輸入輸出的數(shù)據(jù)進(jìn)行打日志,如下:
aspect:第一種方式
@Before 和 @AfterReturning 來(lái)對(duì) controller 進(jìn)行切面。
輸出數(shù)據(jù):
aspect:第二種方式
@Around 來(lái)對(duì)controller 進(jìn)行切面。
輸出數(shù)據(jù):
兩種方法都是能夠?qū)φ?qǐng)求數(shù)據(jù)做日志監(jiān)控。
第一種方式和第二種方式有一些不同,第二種方式使用的是@Around 環(huán)繞的方式去做的處理,joinPoint.proceed()返回?cái)?shù)據(jù)需要等方法執(zhí)行完才能執(zhí)行下面的代碼,這種是阻塞式的請(qǐng)求,所以個(gè)人建議還是采用第一種方法比較合適。
SpringBoot @Aspect注解詳情
1、添加maven依賴(lài)注解
<!--springBoot的aop--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2、添加AOP類(lèi)
@Component @Aspect public class JournalServiceAspect { }
3、設(shè)置切面點(diǎn)
/**切面點(diǎn)*/ private final String POINT_CUT = "execution(* com.xx.xx..*(..))"; @Pointcut(POINT_CUT) private void pointcut(){}
4、配置前置通知
/** * 前置通知,方法調(diào)用前被調(diào)用 * @param joinPoint */ @Before(value = POINT_CUT) public void before(JoinPoint joinPoint){ logger.info("前置通知"); //獲取目標(biāo)方法的參數(shù)信息 Object[] obj = joinPoint.getArgs(); //AOP代理類(lèi)的信息 joinPoint.getThis(); //代理的目標(biāo)對(duì)象 joinPoint.getTarget(); //用的最多 通知的簽名 Signature signature = joinPoint.getSignature(); //代理的是哪一個(gè)方法 logger.info("代理的是哪一個(gè)方法"+signature.getName()); //AOP代理類(lèi)的名字 logger.info("AOP代理類(lèi)的名字"+signature.getDeclaringTypeName()); //AOP代理類(lèi)的類(lèi)(class)信息 signature.getDeclaringType(); //獲取RequestAttributes RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); //從獲取RequestAttributes中獲取HttpServletRequest的信息 HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); //如果要獲取Session信息的話,可以這樣寫(xiě): //HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION); //獲取請(qǐng)求參數(shù) Enumeration<String> enumeration = request.getParameterNames(); Map<String,String> parameterMap = Maps.newHashMap(); while (enumeration.hasMoreElements()){ String parameter = enumeration.nextElement(); parameterMap.put(parameter,request.getParameter(parameter)); } String str = JSON.toJSONString(parameterMap); if(obj.length > 0) { logger.info("請(qǐng)求的參數(shù)信息為:"+str); } }
**注意:這里用到了JoinPoint和RequestContextHolder。
1)、通過(guò)JoinPoint可以獲得通知的簽名信息,如目標(biāo)方法名、目標(biāo)方法參數(shù)信息等。
2)、通過(guò)RequestContextHolder來(lái)獲取請(qǐng)求信息,Session信息。**
5、配置后置返回通知
/** * 后置返回通知 * 這里需要注意的是: * 如果參數(shù)中的第一個(gè)參數(shù)為JoinPoint,則第二個(gè)參數(shù)為返回值的信息 * 如果參數(shù)中的第一個(gè)參數(shù)不為JoinPoint,則第一個(gè)參數(shù)為returning中對(duì)應(yīng)的參數(shù) * returning:限定了只有目標(biāo)方法返回值與通知方法相應(yīng)參數(shù)類(lèi)型時(shí)才能執(zhí)行后置返回通知,否則不執(zhí)行, * 對(duì)于returning對(duì)應(yīng)的通知方法參數(shù)為Object類(lèi)型將匹配任何目標(biāo)返回值 * @param joinPoint * @param keys */ @AfterReturning(value = POINT_CUT,returning = "keys") public void doAfterReturningAdvice1(JoinPoint joinPoint,Object keys){ logger.info("第一個(gè)后置返回通知的返回值:"+keys); } @AfterReturning(value = POINT_CUT,returning = "keys",argNames = "keys") public void doAfterReturningAdvice2(String keys){ logger.info("第二個(gè)后置返回通知的返回值:"+keys); }
6、后置異常通知
/** * 后置異常通知 * 定義一個(gè)名字,該名字用于匹配通知實(shí)現(xiàn)方法的一個(gè)參數(shù)名,當(dāng)目標(biāo)方法拋出異常返回后,將把目標(biāo)方法拋出的異常傳給通知方法; * throwing:限定了只有目標(biāo)方法拋出的異常與通知方法相應(yīng)參數(shù)異常類(lèi)型時(shí)才能執(zhí)行后置異常通知,否則不執(zhí)行, * 對(duì)于throwing對(duì)應(yīng)的通知方法參數(shù)為T(mén)hrowable類(lèi)型將匹配任何異常。 * @param joinPoint * @param exception */ @AfterThrowing(value = POINT_CUT,throwing = "exception") public void doAfterThrowingAdvice(JoinPoint joinPoint,Throwable exception){ //目標(biāo)方法名: logger.info(joinPoint.getSignature().getName()); if(exception instanceof NullPointerException){ logger.info("發(fā)生了空指針異常!!!!!"); } }
7、后置最終通知
/** * 后置最終通知(目標(biāo)方法只要執(zhí)行完了就會(huì)執(zhí)行后置通知方法) * @param joinPoint */ @After(value = POINT_CUT) public void doAfterAdvice(JoinPoint joinPoint){ logger.info("后置最終通知執(zhí)行了!!!!"); }
8、環(huán)繞通知
/** * 環(huán)繞通知: * 環(huán)繞通知非常強(qiáng)大,可以決定目標(biāo)方法是否執(zhí)行,什么時(shí)候執(zhí)行,執(zhí)行時(shí)是否需要替換方法參數(shù),執(zhí)行完畢是否需要替換返回值。 * 環(huán)繞通知第一個(gè)參數(shù)必須是org.aspectj.lang.ProceedingJoinPoint類(lèi)型 */ @Around(value = POINT_CUT) public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint){ logger.info("環(huán)繞通知的目標(biāo)方法名:"+proceedingJoinPoint.getSignature().getName()); try { Object obj = proceedingJoinPoint.proceed(); return obj; } catch (Throwable throwable) { throwable.printStackTrace(); } return null; }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決@FeignClient注入service失敗問(wèn)題
這篇文章主要介紹了解決@FeignClient注入service失敗問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java實(shí)現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語(yǔ)音識(shí)別)
Java中實(shí)現(xiàn)音頻轉(zhuǎn)文本通常涉及使用專(zhuān)門(mén)的語(yǔ)音識(shí)別服務(wù),本文主要介紹了Java實(shí)現(xiàn)音頻轉(zhuǎn)文本的示例代碼(語(yǔ)音識(shí)別),具有一定的參考價(jià)值,感興趣的可以了解一下2024-05-05解決@RequestMapping和@FeignClient放在同一個(gè)接口上遇到的坑
這篇文章主要介紹了解決@RequestMapping和@FeignClient放在同一個(gè)接口上遇到的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07java網(wǎng)絡(luò)編程學(xué)習(xí)java聊天程序代碼分享
java聊天程序代碼分享,大家參考使用吧2013-12-12java如何將list中的某個(gè)元素移動(dòng)位置
在Java編程中我們經(jīng)常會(huì)使用List數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)一組元素,下面這篇文章主要給大家介紹了關(guān)于java如何將list中的某個(gè)元素移動(dòng)位置的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05springboot項(xiàng)目實(shí)現(xiàn)配置跨域
這篇文章主要介紹了springboot項(xiàng)目實(shí)現(xiàn)配置跨域問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09Java 反射修改類(lèi)的常量值、靜態(tài)變量值、屬性值實(shí)例詳解
在本篇文章里小編給大家整理的是一篇關(guān)于Java 反射修改類(lèi)的常量值、靜態(tài)變量值、屬性值實(shí)例詳解內(nèi)容,有興趣的讀者們可以跟著學(xué)習(xí)下。2021-01-01