關於Spring Boot 中AOP攔截入參記錄日誌報錯的原因分析

異常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)


package cn.bainuo.gene.aspect;

import cn.bainuo.gene.common.utils.RedisUserUtil;
import cn.bainuo.gene.security.domain.User;
import cn.bainuo.gene.security.domain.vo.UserInfoVo;
import cn.bainuo.gene.security.service.LoginService;
import cn.bainuo.gene.utils.utils.HttpRequestUtil;
import cn.bainuo.gene.utils.utils.StringUtils;
import cn.bainuo.gene.utils.utils.SystemControllerLog;
import cn.bainuo.gene.utils.utils.SystemServiceLog;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
@SuppressWarnings("all")
public class SystemLogAspect {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private LoginService loginService;


    @Autowired
    private RedisUserUtil redisUserUtil;

    @Pointcut("@annotation(cn.bainuo.gene.utils.utils.SystemServiceLog)")
    public void serviceAspect(){
    }

    @Pointcut("@annotation(cn.bainuo.gene.utils.utils.SystemControllerLog)")
    public void controllerAspect(){
    }

    @Before("controllerAspect()")
    public  void doBefore(JoinPoint joinPoint) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token =(String)request.getAttribute("token");
        String userName="";
        if(StringUtils.isNotBlank(token)) {
            //讀取session中的用戶,注意:proai項目中讀取redis緩存用戶數據異常.
//            UserInfoVo user = redisUserUtil.getCurrentUser(token);
            User userInfoVo = loginService.getUserInfo(token);
            userName=userInfoVo.getUserName();
        }
        //請求的IP
        String ip = request.getRemoteAddr();
        String params = "";
        Object[] arguments  = new Object[joinPoint.getArgs().length];
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
              //這裏出現參數不能轉換問題,想了半天最後發現裏面有request對象不能被序列化
               //最後把這些對象過濾了。
//                params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";  
                if (joinPoint.getArgs()[i] instanceof ServletRequest || joinPoint.getArgs()[i] instanceof ServletResponse || joinPoint.getArgs()[i] instanceof MultipartFile) {
                    //HttpServletRequest不能序列化,從入參裏排除,否則報異常:java.lang.IllegalStateException:
                    // It is illegal to call this method if the current request is not in asynchronous mode
                    // (i.e. isAsyncStarted() returns false)
                    continue;
                }
                arguments[i] = joinPoint.getArgs()[i];
            }
        }
        if (arguments != null  && arguments.length > 0) {
            try {
                params = JSON.toJSONString(arguments);
            } catch (Exception e) {
                params = arguments.toString();
            }
        }

        try {
            //*========控制檯輸出=========*//
            logger.info("=====前置通知開始=====");
            logger.info("請求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            logger.info("方法描述:" + getControllerMethodDescription(joinPoint));
            logger.info("請求人:" + userName);
            logger.info("請求IP:" + ip);
            logger.info("請求參數:" + params);
            logger.info("=====前置通知結束=====");
        }  catch (Exception e) {
            //記錄本地異常日誌
            logger.error("==前置通知異常==");
            logger.error("異常信息:{}", e.getMessage());
        }
    }

    @AfterThrowing(pointcut = "serviceAspect()",throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token =(String)request.getAttribute("token");
        String userName="";
        if(StringUtils.isNotBlank(token)) {
            //讀取session中的用戶 注意:proai項目中讀取redis緩存用戶數據異常.
//            UserInfoVo user = redisUserUtil.getCurrentUser(token);
            User userInfoVo = loginService.getUserInfo(token);
            userName=userInfoVo.getUserName();
        }
        //獲取請求ip
        String ip = HttpRequestUtil.getHost(request);
        //獲取用戶請求方法的參數並序列化爲JSON格式字符串
        String params = "";
        Object[] arguments  = new Object[joinPoint.getArgs().length];
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
//                params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";
                if (joinPoint.getArgs()[i] instanceof ServletRequest || joinPoint.getArgs()[i] instanceof ServletResponse || joinPoint.getArgs()[i] instanceof MultipartFile) {
                    //HttpServletRequest不能序列化,從入參裏排除,否則報異常:java.lang.IllegalStateException:
                    // It is illegal to call this method if the current request is not in asynchronous mode
                    // (i.e. isAsyncStarted() returns false)
                    continue;
                }
                arguments[i] = joinPoint.getArgs()[i];
            }
        }
        if (arguments != null  && arguments.length > 0) {
            try {
                params = JSON.toJSONString(arguments);
            } catch (Exception e1) {
                params = arguments.toString();
            }
        }
        try {
            StackTraceElement s= e.getStackTrace()[0];
            /*========控制檯輸出=========*/
            logger.info("=====異常通知開始=====");
            logger.info("異常代碼類/方法/行數:" +joinPoint.getTarget().getClass().getName()+"/"+s.getMethodName()+"/"+s.getLineNumber());
            /*logger.info("異常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));*/
            logger.info("方法描述:" + getServiceMethodDescription(joinPoint));
            logger.info("請求人:" + userName);
//            logger.info("請求IP:" + ip);
            logger.info("請求參數:" + params);
            logger.info("=====異常通知結束=====");
        } catch (Exception ex) {
            //記錄本地異常日誌
            logger.error("==異常通知異常==");
            logger.error("異常信息:{}", ex.getMessage());
        }
    }

    public static String getServiceMethodDescription(JoinPoint joinPoint)throws Exception{
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method:methods) {
            if (method.getName().equals(methodName)){
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length==arguments.length){
                    description = method.getAnnotation(SystemServiceLog.class).description();
                    break;
                }
            }
        }
        return description;
    }

    public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(SystemControllerLog. class).description();
                    break;
                }
            }
        }
        return description;
    }
}

最初的觀察並沒有發現明顯的問題,因爲paramter本身就是String類型; 後進行debug後,定位出問題所在位置: paramter = JSON.toJSONString(args); 在執行後報錯:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)

上網查詢資料後發現,是因爲使用 Object[] args = joinPoint.getArgs(); 獲取入參的時候,args還包含了一些其他的內容,比如ServletRequest等,而這些入參並不能進行序列化,所以JSON.toJSONString時報錯,只能註釋這行代碼了,重新改造一下,在上面的代碼中已經實現了。

if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
              //這裏出現參數不能轉換問題,想了半天最後發現裏面有request對象不能被序列化
               //最後把這些對象過濾了。
//                params += JSON.toJSON(joinPoint.getArgs()[i]) + ";";  
               
                arguments[i] = joinPoint.getArgs()[i];
            }
        }
       

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章