解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题的方法
解决springboot全局异常处理与aop日志处理中@afterthrowing失效问题的方法
本文讲解"解决springboot全局异常处理与aop日志处理中@afterthrowing失效问题的方法",希望能够解决相关问题。
目录- 一、前言
- 二、问题
- 三、失效场景
一、前言
- 在实际业务场景中,我们通常会使用全局异常处理机制,也就是在业务代码发生异常的时候,拦截异常并进行统一的处理,然后以json格式返回给前端。
- 同时我们也会使用aop进行操作日志记录,在不发生异常时,可以使用四种advice方式记录操作日志:@before(“”),@after(“”)、 @afterreturning(“”)、 @around(“”)。当发生异常时,使用@afterthrowing(value = “”,throwing = “e”)进行日志记录。
二、问题
同时使用上述两种方式,可能出现某一种失效的场景。
三、失效场景
失效场景一: 如果采用前后端不分离架构,采用下属代码返回前端响应结果,如果统一异常处理执行顺序在@afterthrowing之前,就会出现@afterthrowing中不执行情况。前后端分离架构不会出现此问题。
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, "服务器异常!")); } else { response.sendredirect(request.getcontextpath() + "/error"); }
解决方案:让aop日志处理类实现ordered 接口,并重写getorder()方法,使其返回值为1,返回值越小,执行的顺序越靠前,使其执行顺序优先于全部异常处理类。
@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(); } }
失效场景二:如果使用了 @around(“”),在执行 joinpoint.proceed()方法时,捕获了异常,会导致全局异常处理无法收到异常,因此失效。
@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 对象: " + obj); system.out.println("around excute after ········"); }
解决方案:不要进行异常捕获,或者捕获后重新抛出异常。
@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("执行失败",e); } system.out.println("obj 对象: " + obj); system.out.println("around excute after ········"); }
4、测试全部代码
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 { /** * 定义执行顺序的优先级,值越小,优先级越高 * @return */ @override public int getorder() { return 1; } /** * 定义切点(织入点) * execution(* com.nowcoder.community.controller.*.*(..)) * - 第一个 * 表示 支持任意类型返回值的方法 * - com.nowcoder.community.controller 表示这个包下的类 * - 第二个 * 表示 controller包下的任意类 * - 第三个 * 表示 类中的任意方法 * - (..) 表示方法可以拥有任意参数 * 可以根据自己的需求替换。 * */ @pointcut("execution(* com.nowcoder.community.controller.*.*(..))") public void pointcut(){ } /** * 定义 advice 通知 * - 1. @before 目标方法执行之前 * - 2. @after 目标方法执行之后 * - 3. @afterreturning 目标方法返回执行结果之后 * - 4. @afterthrowing 目标方法抛出异常后 * - 5. @around 可以使用proceedingjoinpoint joinpoint,获取目标对象,通过动态代理,代理目标类执行,在目标对象执行前后均可 */ @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; } // 请求ip string ip = attributes.getrequest().getremotehost(); // 请求路径 string requesturi = attributes.getrequest().getrequesturi(); // 请求方法 string requestmethod = attributes.getrequest().getmethod(); system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%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; } // 请求ip string ip = attributes.getrequest().getremotehost(); // 请求路径 string requesturi = attributes.getrequest().getrequesturi(); // 请求方法 string requestmethod = attributes.getrequest().getmethod(); system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%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; } // 请求ip string ip = attributes.getrequest().getremotehost(); // 请求路径 string requesturi = attributes.getrequest().getrequesturi(); // 请求方法 string requestmethod = attributes.getrequest().getmethod(); system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%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; } // 请求ip string ip = attributes.getrequest().getremotehost(); // 请求路径 string requesturi = attributes.getrequest().getrequesturi(); // 请求方法 string requestmethod = attributes.getrequest().getmethod(); system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s],请求失败原因: [%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; } // 请求ip string ip = attributes.getrequest().getremotehost(); // 请求路径 string requesturi = attributes.getrequest().getrequesturi(); // 请求方法 string requestmethod = attributes.getrequest().getmethod(); system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requesturi, requestmethod,classname,methodname)); object obj = null; try { obj = joinpoint.proceed(); } catch (throwable e) { system.out.println("我捕获了异常"); throw new runtimeexception("执行失败",e); } system.out.println(string.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requesturi, requestmethod,classname,methodname)); system.out.println("around excute after ········"); } }
关于 "解决springboot全局异常处理与aop日志处理中@afterthrowing失效问题的方法" 就介绍到此。希望多多支持硕编程。