Spring Webflux – 抛出已检查的自定义异常(而不是RuntimeException)的正确方法

huangapple go评论61阅读模式
英文:

Spring Webflux - Proper way to throw checked custom exception (not RuntimeException)

问题

当我抛出 Spring WebFlux 中的自定义已检查异常时,想请问正确的方法是什么呢?
我想要强调的是,这涉及已检查的自定义异常,比如 MyException.java,而不是像 RuntimeException 这样的内容,同时也是关于抛出异常,而不是处理异常。

我尝试了以下代码:

@Controller
@SpringBootApplication
public class QuestionHowToThrowException {

    public static void main(String[] args) {
        SpringApplication.run(QuestionHowToThrowException.class);
    }

    @PostMapping(path = "/question", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public Mono<ResponseEntity<QuestionResponse>> question(@RequestBody QuestionRequest questionRequest) {
        Mono<FirstStep> firstStepMono = WebClient.create().post().uri("http://firstWebService:8111/getFirstStep")
                .body(questionRequest.getThing(), String.class).retrieve().bodyToMono(FirstStep.class);
        Mono<SecondStep> secondStepMono = firstStepMono.map(oneFirstStep -> getSecondStepFromFirstStepAfterCheck(oneFirstStep));
        return secondStepMono.map(oneSecondStep -> ResponseEntity.ok(new QuestionResponse(oneSecondStep.getSecondThing())));
    }

    private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException {
        if (firstStep.getThingNeedsToCheckCanThrowException().equals("exception")) {
            throw new MyException("exception");
        } else {
            return new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good");
        }
    }

    public class QuestionRequest {
        private String thing;
        public String getThing() {
            return thing;
        }
    }

    public class QuestionResponse {
        private String response;
        public QuestionResponse(String response) {
            this.response = response;
        }
    }

    public class FirstStep {
        private String thingNeedsToCheckCanThrowException;
        public String getThingNeedsToCheckCanThrowException() {
            return thingNeedsToCheckCanThrowException;
        }
    }

    public class SecondStep {
        private String secondThing;
        public SecondStep(String secondThing) {
            this.secondThing = secondThing;
        }
        public String getSecondThing() {
            return secondThing;
        }
    }

}

但是这是不可能的,因为在 getSecondStepFromFirstStepAfterCheck 方法中存在未处理的异常。

如果我抛出并传播异常,private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException,lambda 调用方法会出现问题。

请问在 WebFlux 中抛出自定义异常的最清晰和正确的方法是什么呢?

谢谢

英文:

May I ask what is the proper way to throw checked custom exception in Spring webflux please?
I would like to insist, it is about checked custom exception, like MyException.java, not something like RuntimeException, and it is about throwing exception, not handling exception.

I tried the following :

@Controller
@SpringBootApplication
public class QuestionHowToThrowException {
public static void main(String[] args) {
SpringApplication.run(QuestionHowToThrowException.class);
}
@PostMapping(path = &quot;/question&quot;, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Mono&lt;ResponseEntity&lt;QuestionResponse&gt;&gt; question(@RequestBody QuestionRequest questionRequest) {
Mono&lt;FirstStep&gt; firstStepMono = WebClient.create().post().uri(&quot;http://firstWebService:8111/getFirstStep&quot;)
.body(questionRequest.getThing(), String.class).retrieve().bodyToMono(FirstStep.class);
Mono&lt;SecondStep&gt; secondStepMono = firstStepMono.map(oneFirstStep -&gt; getSecondStepFromFirstStepAfterCheck(oneFirstStep));
return secondStepMono.map(oneSecondStep -&gt; ResponseEntity.ok(new QuestionResponse(oneSecondStep.getSecondThing())));
}
private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException {
if (firstStep.getThingNeedsToCheckCanThrowException().equals(&quot;exception&quot;)) {
throw new MyException(&quot;exception&quot;);
} else {
return new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + &quot;good&quot;);
}
}
public class QuestionRequest {
private String thing;
public String getThing() {
return thing;
}
}
public class QuestionResponse {
private String response;
public QuestionResponse(String response) {
this.response = response;
}
}
public class FirstStep {
private String thingNeedsToCheckCanThrowException;
public String getThingNeedsToCheckCanThrowException() {
return thingNeedsToCheckCanThrowException;
}
}
public class SecondStep {
private String secondThing;
public SecondStep(String secondThing) {
this.secondThing = secondThing;
}
public String getSecondThing() {
return secondThing;
}
}
}

This is not possible, since there in an unhandled exception in getSecondStepFromFirstStepAfterCheck method.

If I throw and propagate, private SecondStep getSecondStepFromFirstStepAfterCheck(FirstStep firstStep) throws MyException the lambda caller method is not happy.

What is the cleanest and proper way to throw custom exception in webflux please?

Thank you

答案1

得分: 1

对于我们的应用程序,我们的自定义基础异常是从RuntimeException派生的。然后,我们有标准的异常处理,会在将结果返回给最终用户之前,寻找我们的自定义异常以进行特殊处理。这允许我们使用正常的throws机制,因为我们希望所有抛出的异常都能传播到调用的最顶层。

出于性能方面的考虑,Webflux和响应式在每次调用的基础上稍微降低了性能,尤其是对于不需要进行任何并行化的调用。然而,一旦系统开始负载,它往往变得更具性能,主要与垃圾收集有关。从map和flatMap之间的差异产生的开销应该可以忽略不计。

英文:

For our applications, we have our custom base exception extend from RuntimeException. We then have standard exception handling that looks for our custom exception for special handling before returning results back to the end user. This allows us to use normal throws mechanics since we want all exceptions thrown to ripple up the top level of the call.

For performance concerns webflux and reactive are slightly lower performance on a per call basis especially for calls that don't need to do any parallelization. However once load is put onto the system it tends to become more performant primarily related to garbage collection. Overhead from the difference between map and flatMap should be negligible at best.

答案2

得分: 1

通过阅读您的示例代码,看起来您正在尝试在Mono上引入一些错误处理。

您可以通过扩展RuntimeException类来创建一个未检查的异常。如果您想要一个强制处理的已检查异常,您可以简单地扩展Exception类。

public class MyException extends RuntimeException {
    public MyException(String msg) {
       super(msg);
    }
}

在Reactor项目中抛出异常的最干净的方式实际上就是抛出它。有一些错误处理函数可以让您为某些错误情况提供不同的流程。

好消息是,您有几种选项可以提供一些错误处理的流程控制。

Project Reactor在Mono对象上提供了几种这样的方法。

doOnError()onErrorContinue()onErrorReturn()onErrorStop()onErrorMap()

我不完全确定您在以下示例代码中尝试实现什么目标。

if (condition) {
    return Mono.error(new MyException("exception"));
} else {
    return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good"));
}

但这看起来像一个适合使用onErrorMap()的好例子,因为您似乎在这里尝试翻译一些异常。

return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + "good"))
   .onErrorMap(e -> "translated result");
英文:

Reading through your sample code, it looks like you are trying to introduce some error handling with on your Mono.

You can create an unchecked exception by extending the RuntimeException class. If you want a checked exception that enforces handling, you can simply extend Exception.

public class MyException extends RuntimeException {
public MyException(String msg) {
super(s);
}
}

The cleanest way to throw an exception with the Reactor project is really just to throw it. There are error handling functions that allow you to provide different flows to certain error cases.

The good news is you have several options that provides some flow control for error handling.

Project Reactor provides several of these methods on the Mono object.

doOnError(),onErrorContinue(),onErrorReturn(),onErrorStop(),onErrorMap()

I am not entirely sure what you are trying to achieve with the following sample code.

 return Mono.error(new MyException(&quot;exception&quot;));
} else {
return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + &quot;good&quot;));

But this looks like a good case for a onErrorMap() since it looks like you are trying to translate some exception here

return Mono.just(new SecondStep(firstStep.getThingNeedsToCheckCanThrowException() + &quot;good&quot;)
.onErrorMap(e -&gt; &quot;translated result&quot;);

huangapple
  • 本文由 发表于 2020年8月25日 07:24:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63569954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定