controller

    @GetMapping("/aspect")
    public Flux<String> testAspect(@RequestParam String name) {
        return Flux.just("tom", "jerry", "jucifer", "kaige")
                   .map(s -> {
                       if ("kaige".equalsIgnoreCase(s)) {
                           throw new RuntimeException("kaige is very handsome");
                       }
                       return s;
                   });
    }

aspect

@Aspect
@Component
@Slf4j
public class FluxAspect {

    @Pointcut("execution(* com.paranoia.webfluxreactive.router..*(..))")
    public void logPointCut() {
    }


    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();

        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        Object[] args = point.getArgs();

        log.info("class :" + className +
                " -> method : -> " + methodName +
                " -> args : -> " + Arrays.toString(args));

        try {
            return point.proceed();
        } catch (Throwable throwable) {
            //经验证,webflux 异常不会在这里被捕获
            throwable.printStackTrace();
            log.error("something wrong : " + throwable.getLocalizedMessage());
            return throwable.getLocalizedMessage();
        }
    }
}

请求:

http://localhost:8080/platform/aspect?name=hi

结果:

字符串‘kaige’并没有返回,说明异常抛出没问题。但是切面并没有像mvc那样将异常捕捉到。

 

重新尝试:

添加一个异常类型的切点

@AfterThrowing(value = "logPointCut()", throwing = "throwable")
    public void tryException(Throwable throwable) {
        System.out.println("throwable = " + throwable);
}

 异常还是没有捕捉到,控制台打印如下:

[ctor-http-nio-3] c.p.webfluxreactive.aspect.FluxAspect    : class :com.paranoia.webfluxreactive.router.SysPlatformController -> method : -> testAspect -> args : -> [hi]
[ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : Unhandled failure: kaige is very handsome, response already set (status=null)
[ctor-http-nio-3] o.s.h.s.r.ReactorHttpHandlerAdapter      : Handling completed with error: kaige is very handsome

目测是ReactorHttpHandlerAdapter  这个类将异常处理掉了。

再次尝试:ControllerAdvice

@ControllerAdvice
@Slf4j
public class GloableExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String gloabExceptionHandler(Exception e){
        log.error("操作失败",e);
        return "操作失败";
    }
}

结果:

[ctor-http-nio-3] c.p.webfluxreactive.aspect.FluxAspect    : class :com.paranoia.webfluxreactive.router.SysPlatformController -> method : -> testAspect -> args : -> [hi]
[ctor-http-nio-3] c.p.w.exception.GloableExceptionHandler  : 操作失败

java.lang.RuntimeException: kaige is very handsome
	at com.paranoia.webfluxreactive.router.SysPlatformController.lambda$testAspect$0(SysPlatformController.java:54) ~[classes/:na]
	at ...

 [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : Unhandled failure: null, response already set (status=null)
[ctor-http-nio-3] o.s.h.s.r.ReactorHttpHandlerAdapter      : Handling completed with error: null

发现handler提前于Adapter前将异常捕捉处理掉,Adapter打印的是Handling completed with error: null,它并没有拿到异常信息。

 

总结:

  1. webflux和webmvc切面的逻辑上有区别。flux可以和mvc一样拿到请求信息,但是拿不到异常信息。
  2. ExceptionHandler一如既往可以正常拿到异常信息。

fixme:

  1. ReactorHttpHandlerAdapter 在异常流程中的担任什么角色?
  2. 异常上下文如何贯穿起来?