每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

若依远程调用异步方法AOP日志无法写入

问题场景描述:

修改菜单是远程异步方法可以正常写入日志,但无法写入业务操作日志.异常如下:

/**
 * 保存系统日志记录
 */
@Async //取消异步请求可以正常写入日志,但为了用户体验效果和运行速度后来想来想去还是异步快。
public void saveSysLog(SysOperLog sysOperLog){
    remoteOperLogService.saveLog(sysOperLog);
}

目前系统写入日志流程如下
1、safe-business 模块->调用者
2、ruoyi-common-log 模块->异步方法
3、ruoyi-common-log 模块->操作日志远程服务接口 feign api
4、ruoyi-api-system 模块->system模块controller
5、ruoyi-system 模块->service-impl-mapper

@PostMapping
@ResponseBody
@Log(title = "测试", businessType = BusinessType.UPDATE)
public AjaxResult add(@RequestBody Demo demo) {
    System.out.println(demo.getName());
    return AjaxResult.success(null);
}
/**
 * 自定义操作日志记录注解
 * 
 * @author 黑猫
 *
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
    /**
     * 模块
     */
    public String title() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

    /**
     * 操作人类别
     */
    public OperatorType operatorType() default OperatorType.PC;

    /**
     * 是否保存请求的参数
     */
    public boolean isSaveRequestData() default true;
}
/**
 * 操作日志记录处理
 * 
 * @author 黑猫
 */
@Aspect
@Component
public class LogAspect{ 
	protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try
        {
            // 获得注解
            Log controllerLog = getAnnotationLog(joinPoint);
            if (controllerLog == null)
            {
                return;
            }

            // *========数据库日志=========*//
            SysOperLog operLog = new SysOperLog();
            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
            // 请求的地址
            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
            operLog.setOperIp(ip);
            // 返回参数
            operLog.setJsonResult(JSON.toJSONString(jsonResult));

            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
            String username = SecurityUtils.getUsername();
            if (StringUtils.isNotBlank(username))
            {
                operLog.setOperName(username);
            }

            if (e != null)
            {
                operLog.setStatus(BusinessStatus.FAIL.ordinal());
                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
            }
            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");
            // 设置请求方式
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            // 处理设置注解上的参数
            getControllerMethodDescription(joinPoint, controllerLog, operLog);
            // 保存数据库
            asyncLogService.saveSysLog(operLog);//主要看这行代码
        }
        catch (Exception exp)
        {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }
}
/**
 * 异步调用日志服务
 * 
 * @author 黑猫
 */
@Service
public class AsyncLogService
{
    @Autowired
    private RemoteLogService remoteLogService;
    @Autowired
    private RemoteOperLogService remoteOperLogService;

    /**
     * 保存系统日志记录
     */
    @Async
    public void saveSysLog(SysOperLog sysOperLog)
    {
        remoteOperLogService.saveLog(sysOperLog);
    }


}
/** 操作日志远程服务接口
 * @Author: 黑猫
 * @Date: 2022/6/28 15:41
 */
@FeignClient(contextId = "remoteOperLogService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = RemoteOperLogFallbackFactory.class)
public interface RemoteOperLogService
{
    /**
     * 保存系统日志
     * @param sysOperLog 日志实体
     * @return 结果
     */
    @PostMapping("/operlog")
    R<Boolean> saveLog(@RequestBody SysOperLog sysOperLog);

    /**
     * 保存业务操作日志记录
     * @param operLog 业务日志实体
     * @return
     */
    @PostMapping("/businessoperlog")
    R<Boolean> saveBusinessOperLog(@RequestBody JsjdBusinessOperLog operLog);
}
/**
 * 操作日志记录
 * @Author: 黑猫
 * @Date: 2022/6/28 15:41
 */
@RestController
@RequestMapping("/operlog")
public class SysOperlogController extends BaseController
{
    @PostMapping
    public AjaxResult add(@RequestBody SysOperLog operLog)
    {
        return toAjax(operLogService.insertOperlog(operLog));
    }
}

其它的代码就忽略了。

最后发现本人的问题处在FeignSecureRequestInterceptor拦截器上. 注释掉就可以正常了。

/** feign拦截器:请求header传递
 * @Author: 黑猫
 * @Date: 2022/6/28 15:41
 */

@Component
public class FeignSecureRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                requestTemplate.header(name, values);
            }
        }
    }
}

总结:

1:启动类添加@EnableAsync注解
2:异步方法添加@async注解

注意:异步方法跟调用异步的方法不能在同一个类,如果同一个类里放就等于同步不生效。

posted @ 2022-06-28 10:54  星星之草%  阅读(1180)  评论(1编辑  收藏  举报