解決Springboot全局異常處理與AOP日志處理中@AfterThrowing失效問(wèn)題的方法
解決springboot全局異常處理與aop日志處理中@afterthrowing失效問(wèn)題的方法
本文講解"解決springboot全局異常處理與aop日志處理中@afterthrowing失效問(wèn)題的方法",希望能夠解決相關(guān)問(wèn)題。
目錄- 一、前言
- 二、問(wèn)題
- 三、失效場(chǎng)景
一、前言
- 在實(shí)際業(yè)務(wù)場(chǎng)景中,我們通常會(huì)使用全局異常處理機(jī)制,也就是在業(yè)務(wù)代碼發(fā)生異常的時(shí)候,攔截異常并進(jìn)行統(tǒng)一的處理,然后以json格式返回給前端。
- 同時(shí)我們也會(huì)使用aop進(jìn)行操作日志記錄,在不發(fā)生異常時(shí),可以使用四種advice方式記錄操作日志:@before(“”),@after(“”)、 @afterreturning(“”)、 @around(“”)。當(dāng)發(fā)生異常時(shí),使用@afterthrowing(value = “”,throwing = “e”)進(jìn)行日志記錄。
二、問(wèn)題
同時(shí)使用上述兩種方式,可能出現(xiàn)某一種失效的場(chǎng)景。
三、失效場(chǎng)景
失效場(chǎng)景一: 如果采用前后端不分離架構(gòu),采用下屬代碼返回前端響應(yīng)結(jié)果,如果統(tǒng)一異常處理執(zhí)行順序在@afterthrowing之前,就會(huì)出現(xiàn)@afterthrowing中不執(zhí)行情況。前后端分離架構(gòu)不會(huì)出現(xiàn)此問(wèn)題。
string?xrequestedwith?=?request.getheader("x-requested-with"); if?("xmlhttprequest".equals(xrequestedwith))?{ ????response.setcontenttype("application/plain;charset=utf-8"); ????printwriter?writer?=?response.getwriter(); ????writer.write(communityutil.getjsonstring(1,?"服務(wù)器異常!")); }?else?{ ????response.sendredirect(request.getcontextpath()?+?"/error"); }
解決方案:讓aop日志處理類實(shí)現(xiàn)ordered 接口,并重寫(xiě)getorder()方法,使其返回值為1,返回值越小,執(zhí)行的順序越靠前,使其執(zhí)行順序優(yōu)先于全部異常處理類。
@component @aspect public?class?logaspecttest?implements?ordered?{ ????@override ????public?int?getorder()?{ ????????return?1; ????} ????????@afterthrowing(value?=?"pointcut()",throwing?=?"e") ????public?void?afterthrowing(joinpoint?joinpoint,exception?e){ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????system.out.println("classname?is?:?"?+?classname?+?".?methodname?is?:?"?+?methodname); ????????system.out.println("afterthrowing?excute········"?+?e.getmessage()); ????????e.printstacktrace(); ????} }
失效場(chǎng)景二:如果使用了 @around(“”),在執(zhí)行 joinpoint.proceed()方法時(shí),捕獲了異常,會(huì)導(dǎo)致全局異常處理無(wú)法收到異常,因此失效。
@around("pointcut()") public?void?around(proceedingjoinpoint?joinpoint)?throws?throwable?{ ????string?classname?=?joinpoint.gettarget().getclass().getname(); ????string?methodname?=?joinpoint.getsignature().getname(); ????system.out.println("classname?is?:?"?+?classname?+?".?methodname?is?:?"?+?methodname); ????system.out.println("around?excute?before?········"); ????object?obj?=?null; ????try?{ ????????obj?=?joinpoint.proceed(); ????}?catch?(throwable?e)?{ ????????system.out.println("我捕獲了異常"); ????} ????system.out.println("obj?對(duì)象:?"?+?obj); ????system.out.println("around?excute?after?········"); }
解決方案:不要進(jìn)行異常捕獲,或者捕獲后重新拋出異常。
@around("pointcut()") public?void?around(proceedingjoinpoint?joinpoint)?throws?throwable?{ ????string?classname?=?joinpoint.gettarget().getclass().getname(); ????string?methodname?=?joinpoint.getsignature().getname(); ????system.out.println("classname?is?:?"?+?classname?+?".?methodname?is?:?"?+?methodname); ????system.out.println("around?excute?before?········"); ????object?obj?=?null; ????try?{ ????????obj?=?joinpoint.proceed(); ????}?catch?(throwable?e)?{ ????????system.out.println("我捕獲了異常"); ????????throw?new?runtimeexception("執(zhí)行失敗",e); ????} ????system.out.println("obj?對(duì)象:?"?+?obj); ????system.out.println("around?excute?after?········"); }
4、測(cè)試全部代碼
package?com.nowcoder.community.aspect; import?org.aspectj.lang.joinpoint; import?org.aspectj.lang.proceedingjoinpoint; import?org.aspectj.lang.annotation.*; import?org.springframework.core.ordered; 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; /** ?*?@description?aop?日志記錄 ?*/ @component @aspect public?class?logaspecttest?implements?ordered?{ ????/** ?????*?定義執(zhí)行順序的優(yōu)先級(jí),值越小,優(yōu)先級(jí)越高 ?????*?@return ?????*/ ????@override ????public?int?getorder()?{ ????????return?1; ????} ????/** ?????*?定義切點(diǎn)(織入點(diǎn)) ?????*??execution(*?com.nowcoder.community.controller.*.*(..)) ?????*??????-?第一個(gè)?*?表示?支持任意類型返回值的方法 ?????*??????-?com.nowcoder.community.controller?表示這個(gè)包下的類 ?????*??????-?第二個(gè)?*?表示?controller包下的任意類 ?????*??????-?第三個(gè)?*?表示?類中的任意方法 ?????*??????-?(..)?表示方法可以擁有任意參數(shù) ?????*???可以根據(jù)自己的需求替換。 ?????* ?????*/ ????@pointcut("execution(*?com.nowcoder.community.controller.*.*(..))") ????public?void?pointcut(){ ????} ????/** ?????*?定義?advice?通知 ?????*????-?1.?@before?目標(biāo)方法執(zhí)行之前 ?????*????-?2.?@after??目標(biāo)方法執(zhí)行之后 ?????*????-?3.?@afterreturning?目標(biāo)方法返回執(zhí)行結(jié)果之后 ?????*????-?4.?@afterthrowing?目標(biāo)方法拋出異常后 ?????*????-?5.?@around?可以使用proceedingjoinpoint?joinpoint,獲取目標(biāo)對(duì)象,通過(guò)動(dòng)態(tài)代理,代理目標(biāo)類執(zhí)行,在目標(biāo)對(duì)象執(zhí)行前后均可 ?????*/ ????@before("pointcut()") ????public?void?before(joinpoint?joinpoint){ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????servletrequestattributes?attributes?=?(servletrequestattributes)requestcontextholder.getrequestattributes(); ????????if?(attributes?==?null){ ????????????return; ????????} ????????//?請(qǐng)求ip ????????string?ip?=?attributes.getrequest().getremotehost(); ????????//?請(qǐng)求路徑 ????????string?requesturi?=?attributes.getrequest().getrequesturi(); ????????//?請(qǐng)求方法 ????????string?requestmethod?=?attributes.getrequest().getmethod(); ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s]",?ip,requesturi, ????????????????requestmethod,classname,methodname)); ????????system.out.println("before?excute········"); ????} ????@after("pointcut()") ????public?void?after(joinpoint?joinpoint){ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????servletrequestattributes?attributes?=?(servletrequestattributes)requestcontextholder.getrequestattributes(); ????????if?(attributes?==?null){ ????????????return; ????????} ????????//?請(qǐng)求ip ????????string?ip?=?attributes.getrequest().getremotehost(); ????????//?請(qǐng)求路徑 ????????string?requesturi?=?attributes.getrequest().getrequesturi(); ????????//?請(qǐng)求方法 ????????string?requestmethod?=?attributes.getrequest().getmethod(); ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s]",?ip,requesturi, ?????????????????????????????????????????requestmethod,classname,methodname)); ????????system.out.println("after?excute········"); ????} ????@afterreturning("pointcut()") ????public?void?afterreturning(joinpoint?joinpoint){ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????servletrequestattributes?attributes?=?(servletrequestattributes)requestcontextholder.getrequestattributes(); ????????if?(attributes?==?null){ ????????????return; ????????} ????????//?請(qǐng)求ip ????????string?ip?=?attributes.getrequest().getremotehost(); ????????//?請(qǐng)求路徑 ????????string?requesturi?=?attributes.getrequest().getrequesturi(); ????????//?請(qǐng)求方法 ????????string?requestmethod?=?attributes.getrequest().getmethod(); ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s]",?ip,requesturi, ?????????????????????????????????????????requestmethod,classname,methodname)); ????????system.out.println("afterreturning?excute········"); ????} ????@afterthrowing(value?=?"pointcut()",throwing?=?"e") ????public?void?afterthrowing(joinpoint?joinpoint,exception?e){ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????servletrequestattributes?attributes?=?(servletrequestattributes)requestcontextholder.getrequestattributes(); ????????if?(attributes?==?null){ ????????????return; ????????} ????????//?請(qǐng)求ip ????????string?ip?=?attributes.getrequest().getremotehost(); ????????//?請(qǐng)求路徑 ????????string?requesturi?=?attributes.getrequest().getrequesturi(); ????????//?請(qǐng)求方法 ????????string?requestmethod?=?attributes.getrequest().getmethod(); ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s],請(qǐng)求失敗原因:?[%s]",?ip, ?????????????????????????????????????????requesturi,?requestmethod,classname,methodname,e.getmessage()+e.getcause())); ????????system.out.println("afterthrowing?excute········"?+?e.getmessage()); ????????e.printstacktrace(); ????} ????@around("pointcut()") ????public?void?around(proceedingjoinpoint?joinpoint)?throws?throwable?{ ????????string?classname?=?joinpoint.gettarget().getclass().getname(); ????????string?methodname?=?joinpoint.getsignature().getname(); ????????system.out.println("classname?is?:?"?+?classname?+?".?methodname?is?:?"?+?methodname); ????????servletrequestattributes?attributes?=?(servletrequestattributes)requestcontextholder.getrequestattributes(); ????????if?(attributes?==?null){ ????????????return; ????????} ????????//?請(qǐng)求ip ????????string?ip?=?attributes.getrequest().getremotehost(); ????????//?請(qǐng)求路徑 ????????string?requesturi?=?attributes.getrequest().getrequesturi(); ????????//?請(qǐng)求方法 ????????string?requestmethod?=?attributes.getrequest().getmethod(); ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s]",?ip,requesturi, ?????????????????????????????????????????requestmethod,classname,methodname)); ????????object?obj?=?null; ????????try?{ ????????????obj?=?joinpoint.proceed(); ????????}?catch?(throwable?e)?{ ????????????system.out.println("我捕獲了異常"); ????????????throw?new?runtimeexception("執(zhí)行失敗",e); ????????} ????????system.out.println(string.format("用戶:?[%s]?的請(qǐng)求路徑為:[%s],?請(qǐng)求方式為:?[%s],請(qǐng)求類名為:?[%s],?請(qǐng)求方法名為:?[%s]",?ip,requesturi, ?????????????????????????????????????????requestmethod,classname,methodname)); ????????system.out.println("around?excute?after?········"); ????} }
關(guān)于 "解決springboot全局異常處理與aop日志處理中@afterthrowing失效問(wèn)題的方法" 就介紹到此。希望多多支持碩編程。