异步记录日志+获取异步处理结果

一.异步记录日志

1.场景

有事务的情况下,记录将异常信息记录到异常表中

2.处理过程

2.1本来是加上never或者notsurport注解,然后在throw抛异常之前把异常信息插入数据库,但是未成功,抛异常时回滚

2.2finally中调用被@Async注解的方法

2.3注意 这个带@Async注解的方法要放在其他的类里边

调用代码

    public Object logHandler(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        String methodDeclaringClass = method.getDeclaringClass().getSimpleName();
        Object[] args = proceedingJoinPoint.getArgs();
        String targetMethodParams= Arrays.toString(args);//TODO 入参取的不对
        long startTime = System.currentTimeMillis();
        log.info("调用方法:【{}.{}】 开始!入参是【{}】", methodDeclaringClass, methodName,targetMethodParams);
        //异常记录表
        Pf1013 pf1013 = new Pf1013();
        try {
            return proceedingJoinPoint.proceed();
        } catch (Exception exception) {
            log.error("exception,调用方法:【{}.{}】 入参是【{}】,操作人是【{}】",methodDeclaringClass, methodName,targetMethodParams,GlobalVarValueUtil.getOperCode());
            pf1013.setErrorInfo(ExceptionUtils.getStackTrace(exception).substring(0,8000));
            throw exception;
        }  finally {
            //异步存表
            flowAsyncHelper.savePlatExceptionLog(pf1013);
            log.info("调用方法:【{}.{}】 结束,耗时:{}ms, 请求参数【{}】", methodDeclaringClass, methodName,System.currentTimeMillis()-startTime,targetMethodParams);
        }
    }

async注解代码

@Component
@Slf4j
public class AsyncHelper {

    @Autowired
   private Pf1013Mapper pf1013Mapper;

    /**
     * 记录异常日志
     *
     */
    @Async//(AsyncConfig.LOCAL_FLOW_EXECUTOR)
    public void savePlatExceptionLog(Pf1013 pf1013) {
        if(StringUtils.isNotEmpty(pf1013.getErrorInfo())){
            pf1013Mapper.insert(pf1013);
        }
    }

}

奇怪的是,没有配置configuration也没有在启动类中@EnableAsync就好用了,眼睁睁看到抛出异常之后我的异常表里边就有数据了

续集来了

以上操作之后  本地确实是好用的   但是 线上确实是不好用的

所以  使用@async还是有注意事项的

1.异步方法和调用异步方法的方法不能再同一个类

2.异步方法加注解@Async,调用异步方法的方法所在类要加注解@EnableAsync

3.方法所属的类的对象需要是被Spring容器所管理的,也就是指被@Controller @Service @Repository @Component这些注解的类

修改方法  在上边第一段代码loghandler方法所在类上边开启异步  

因为loghandler是调用@async方法的类

后续

另一个项目我也想异步记录日志,有一个参数我在异步之前的调用类可以获取到但是在async这个类里边获取不到,点进去看,原来这个参数存储在线程变量中,然而异步是单独开出来一个线程,所以获取不到

protected static ThreadLocalStack<Map<Class<?>, Object>> contextualData = new ThreadLocalStack();

二.获取异步处理结果

1.AsyncResult

异步想获得执行结果,需要将被@Async注解的方法改为Future返回,使用AsyncResult


    /**
     * 参数分类表发布到指定城市
     * @param pb207
     * @param cityId
     */
    @DataSourceKey(spel = "#cityId")
    @Async
    public Future<Boolean> publishPb207(PB207 pb207, String cityId){
        //发布之前查询指定城市数据库中的pb207中是否存在相应csflm数据,存在就不发布
        PB207 pb207City = pb207Mapper.selectByPrimaryKey(pb207.getCsflm());
        if(ObjectUtils.isEmpty(pb207City)){
            pb207Mapper.insert(pb207);
            return new AsyncResult<>(Boolean.valueOf(false));
        }
        return new AsyncResult<>(Boolean.valueOf(true));//指定城市是否存在参数分类数据
    }

2.Future.get

异步阻塞

首先,同步异步,阻塞非阻塞,是两个概念

 Future<Boolean> exits = publishUtil.publishPb207(pb207, publishCityId);//返回指定城市是否存在参数分类数据
        //4.通过pb207的yjywflbm和ejywflbm,分别查询pb205一级业务分类表和pb206二级业务分类表,如果指定城市有数据就不发布,没数据就发布
        Boolean aBoolean = exits.get();
        if(!aBoolean){}

3.代码改进

之前之所以用异步,是因为要进入同事写的拦截方法,又不知道如何开启新事物

现在想起来,其实只要用@Transactional(propagation= Propagation.REQUIRES_NEW)开启新事物,就不用Future.get了

@Transactional(propagation= Propagation.REQUIRES_NEW)


版权声明:本文为qq_35653822原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。