gpt4 book ai didi

java - Spring ControllerAdvice 不会因某些异常而触发其他异常

转载 作者:行者123 更新时间:2023-12-01 10:09:03 24 4
gpt4 key购买 nike

我有一个 springboot Rest 服务,可以通过 /test 端点访问。我已经设置了一个错误处理 Controller ,如下所示:

@ControllerAdvice
public class AppErrorController extends ResponseEntityExceptionHandler {

@ExceptionHandler(InvalidHeaderException.class)
public ResponseEntity<JsonNode> handleHeaderError(InvalidHeaderException ex) {
return ResponseEntity
.status(HttpStatus.NOT_ACCEPTABLE)
.body(generateResponseJson(ex));
}

@ExceptionHandler(InvalidRequestException.class)
public ResponseEntity<JsonNode> handleRequestError(InvalidRequestException ex) {
return ResponseEntity
.status(HttpStatus.NOT_ACCEPTABLE)
.body(generateResponseJson(ex));
}

@ExceptionHandler(ServiceResponseException.class)
public ResponseEntity<JsonNode> handleServiceError(ServiceResponseException ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(generateResponseJson(ex));
}

private JsonNode generateResponseJson(Exception ex) {
return ResponseBuilder.newBuilder()
.withException(ex.getClass().getSimpleName())
.withDescription(ex.getMessage())
.withTimestamp(LocalDateTime.now())
.buildAsJson();
}
}

我已经对此进行了测试,效果非常好。如果我使用错误的输入测​​试 api,则会返回:

{
"exception": "InvalidRequestException",
"description": "A valid input value is needed that is non-empty or non-null.",
"timestamp": "2016-03-28T11:35:39.765"
}

这就是与处理异常的 AppErrorController 相关的日志:

11:35:39.706 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'Foo_Engine' processing POST request for [/test]
11:35:39.706 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test
11:35:39.707 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Returning handler method [public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.FooController.getFoosForRest(controllers.model.Request,org.springframework.validation.BindingResult)]
11:35:39.708 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Read [class controllers.model.Request] as "application/json" with [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@3086f443]
11:35:39.709 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Resolving exception from handler [public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.FooController.getFoosForRest(controllers.model.Request,org.springframework.validation.BindingResult)]: controllers.exceptions.InvalidRequestException: A valid input value is needed that is non-empty or non-null.
11:35:39.761 [http-bio-8080-exec-3] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appErrorController'
11:35:39.762 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Invoking @ExceptionHandler method: public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.AppErrorController.handleRequestError(controllers.exceptions.InvalidRequestException)
11:35:39.815 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Written [{"resultCode":false,"exception":"InvalidRequestException","description":"A valid input value is needed that is non-empty or non-null.","timestamp":"2016-03-28T11:35:39.765"}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@3086f443]
11:35:39.816 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'Foo_Engine': assuming HandlerAdapter completed request handling
11:35:39.816 [http-bio-8080-exec-3] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request

这在处理 InvalidHeaderExceptionInvalidRequestException 时效果很好,但由于某种原因,它不适用于 ServiceResponseException。第一个异常由 header 拦截器抛出,第二个异常由位于顶部的 Controller 抛出,第三个异常由内部代码抛出。这是抛出的地方:

public class Foo {
private final Cache<String, List<Foo>> fooCache;

public Foo() {
fooCache = CacheBuilder.newBuilder().build();
}

public List<Foo> getFoo() {
List<Foo> foos = null;
try {
foos = fooCache.get(foo.getId(),
() -> populateCacheWithFoo());
} catch (ExecutionException e) {
e.printStackTrace();
}
return foos;
}

public List<Foo> populateCacheWithFoo() {
JsonNode response = null;
try {
response = operation.postForObject(/* resource url */,
/* build header body */,
JsonNode.class);
} catch (Throwable t) {
throw new ServiceResponseException("Error with backend service - getResourceA operation");
}

List<Foo> foos = response.get("Foos");

fooCache.put(foo.get(1).getId(), foos);
return foos;
}
}

出于某种原因,每当我抛出此异常时,它都不会被 AppErrorController 捕获,而是得到以下堆栈跟踪:

11:23:43.085 [http-bio-8080-exec-1] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Resolving exception from handler [public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.FooController.getFoosForRest(controllers.model.Request,org.springframework.validation.BindingResult)]: com.google.common.util.concurrent.UncheckedExecutionException: controllers.exceptions.ServiceResponseException: Error with backend service - getResourceA operation
11:23:43.086 [http-bio-8080-exec-1] DEBUG org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver - Resolving exception from handler [public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.FooController.getFoosForRest(controllers.model.Request,org.springframework.validation.BindingResult)]: com.google.common.util.concurrent.UncheckedExecutionException: controllers.exceptions.ServiceResponseException: Error with backend service - getResourceA operation
11:23:43.086 [http-bio-8080-exec-1] DEBUG org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolving exception from handler [public org.springframework.http.ResponseEntity<com.fasterxml.jackson.databind.JsonNode> controllers.FooController.getFoosForRest(controllers.model.Request,org.springframework.validation.BindingResult)]: com.google.common.util.concurrent.UncheckedExecutionException: controllers.exceptions.ServiceResponseException: Error with backend service - getResourceA operation
11:23:43.096 [http-bio-8080-exec-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Could not complete request
com.google.common.util.concurrent.UncheckedExecutionException: controllers.exceptions.ServiceResponseException: Error with backend service - getResourceA operation
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2207)
at com.google.common.cache.LocalCache.get(LocalCache.java:3953)
at com.google.common.cache.LocalCache$LocalManualCache.get(LocalCache.java:4790)
at services.Foo.getFoo(IdentityClientImpl.java:73)
at controllers.FooController.getFoosForRest(FooController.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:120)
at org.springframework.boot.context.web.ErrorPageFilter.access$000(ErrorPageFilter.java:61)
at org.springframework.boot.context.web.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:95)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.context.web.ErrorPageFilter.doFilter(ErrorPageFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: controllers.exceptions.ServiceResponseException: Error with backend service - getResourceA operation
at services.Foo.populateCacheWithFoo(Foo.java:99)
at services.Foo.lambda$getFoo$0(Foo.java:74)
at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4793)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3542)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2323)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2286)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2201)
... 56 common frames omitted

知道为什么前 2 个异常会被 AppErrorController 捕获,但第三个异常不会被捕获吗?我的 java 配置文件中需要做一些配置吗?这是我的 mvc 配置文件:

@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Autowired
ServletContext servletContext;

@Autowired
HeaderInterceptor interceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}

@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}

@Bean
public ViewResolver getJspViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("WEB-INF/jsp/views/");
resolver.setSuffix(".jsp");
resolver.setOrder(1);
return resolver;
}
}

最佳答案

问题似乎是 guava get 缓存中的 Callable 捕获了异常并重新将它们封装起来:http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/cache/Cache.html#get(K,%20java.util.concurrent.Callable)

您可能需要在 getFoo() 方法中添加一个 catch 子句并重新抛出原始异常。像这样的事情:

public List<Foo> getFoo() throws ServiceResponseException{
List<Foo> foos = null;
try {
foos = fooCache.get(foo.getId(),
() -> populateCacheWithFoo());
} catch (ExecutionException e) {
Throwables.propagateIfPossible(
e.getCause(), ServiceResponseException.class);
}
return foos;
}

但是您可能想在 catch 中放置一个断点,以确认 .getCause() 是您的实际异常,或者它是否处于以下级别

<小时/>

或者,如果您不想将 ServiceException 更改为已检查异常,则可以这样做:

public List<Foo> getFoo() throws ServiceResponseException{
List<Foo> foos = null;
try {
foos = fooCache.get(foo.getId(),
() -> populateCacheWithFoo());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (UncheckedExecutionException e) {
Throwables.propagateIfPossible(
e.getCause(), ServiceResponseException.class);
}
return foos;
}

关于java - Spring ControllerAdvice 不会因某些异常而触发其他异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36265937/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com