下面列出了org.springframework.context.ApplicationContextAware#org.springframework.web.servlet.HandlerExceptionResolver 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
if (handlerExceptionResolvers == null) {
return;
}
for (HandlerExceptionResolver resolver : handlerExceptionResolvers) {
if (resolver instanceof ApplicationContextAware) {
((ApplicationContextAware) resolver).setApplicationContext(getApplicationContext());
}
if (resolver instanceof InitializingBean) {
try {
((InitializingBean) resolver).afterPropertiesSet();
}
catch (Exception ex) {
throw new IllegalStateException("Failure from afterPropertiesSet", ex);
}
}
exceptionResolvers.add(resolver);
}
}
@Test
public void configureExceptionResolvers() throws Exception {
List<WebMvcConfigurer> configurers = new ArrayList<>();
configurers.add(new WebMvcConfigurer() {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
});
delegatingConfig.setConfigurers(configurers);
HandlerExceptionResolverComposite composite =
(HandlerExceptionResolverComposite) delegatingConfig
.handlerExceptionResolver(delegatingConfig.mvcContentNegotiationManager());
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}
/**
* Resolve the exception by iterating over the list of configured exception resolvers.
* <p>The first one to return a {@link ModelAndView} wins. Otherwise {@code null}
* is returned.
*/
@Override
@Nullable
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler,Exception ex) {
if (this.resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
@Test
public void testRollbarExceptionResolver() {
Exception testException = new Exception("test exception");
// build the Rollbar mock object
Rollbar rollbar = mock(Rollbar.class);
doNothing().when(rollbar).error(testException);
// construct exception resolver from the Rollbar resolver for Spring webmvc
HandlerExceptionResolver handlerExceptionResolver = new RollbarHandlerExceptionResolver(rollbar);
// build a full mocked out request for the exception resolver
handlerExceptionResolver.resolveException(request, response, null, testException);
// verify that the rollbar mocked object got the exception inside the resolver
verify(rollbar, times(1)).error(testException);
}
@Override
protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
if (handlerExceptionResolvers == null) {
return;
}
for (HandlerExceptionResolver resolver : handlerExceptionResolvers) {
if (resolver instanceof ApplicationContextAware) {
ApplicationContext applicationContext = getApplicationContext();
if (applicationContext != null) {
((ApplicationContextAware) resolver).setApplicationContext(applicationContext);
}
}
if (resolver instanceof InitializingBean) {
try {
((InitializingBean) resolver).afterPropertiesSet();
}
catch (Exception ex) {
throw new IllegalStateException("Failure from afterPropertiesSet", ex);
}
}
exceptionResolvers.add(resolver);
}
}
/**
* Resolve the exception by iterating over the list of configured exception resolvers.
* The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
*/
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
if (resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
/**
* A method available to subclasses for adding default {@link HandlerExceptionResolver}s.
* <p>Adds the following exception resolvers:
* <ul>
* <li>{@link ExceptionHandlerExceptionResolver}
* for handling exceptions through @{@link ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver}
* for exceptions annotated with @{@link ResponseStatus}.
* <li>{@link DefaultHandlerExceptionResolver}
* for resolving known Spring exception types
* </ul>
*/
protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();
exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager());
exceptionHandlerResolver.setMessageConverters(getMessageConverters());
exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());
exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());
if (jackson2Present) {
exceptionHandlerResolver.setResponseBodyAdvice(
Collections.<ResponseBodyAdvice<?>>singletonList(new JsonViewResponseBodyAdvice()));
}
exceptionHandlerResolver.setApplicationContext(this.applicationContext);
exceptionHandlerResolver.afterPropertiesSet();
exceptionResolvers.add(exceptionHandlerResolver);
ResponseStatusExceptionResolver responseStatusResolver = new ResponseStatusExceptionResolver();
responseStatusResolver.setMessageSource(this.applicationContext);
exceptionResolvers.add(responseStatusResolver);
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
@Test
public void exceptionResolvers() throws Exception {
List<HandlerExceptionResolver> resolvers = ((HandlerExceptionResolverComposite)
this.config.handlerExceptionResolver(null)).getExceptionResolvers();
assertEquals(2, resolvers.size());
assertEquals(ResponseStatusExceptionResolver.class, resolvers.get(0).getClass());
assertEquals(SimpleMappingExceptionResolver.class, resolvers.get(1).getClass());
}
@Test
@SuppressWarnings("unchecked")
public void handlerExceptionResolver() throws Exception {
ApplicationContext context = initContext(WebConfig.class);
HandlerExceptionResolverComposite compositeResolver =
context.getBean("handlerExceptionResolver", HandlerExceptionResolverComposite.class);
assertEquals(0, compositeResolver.getOrder());
List<HandlerExceptionResolver> expectedResolvers = compositeResolver.getExceptionResolvers();
assertEquals(ExceptionHandlerExceptionResolver.class, expectedResolvers.get(0).getClass());
assertEquals(ResponseStatusExceptionResolver.class, expectedResolvers.get(1).getClass());
assertEquals(DefaultHandlerExceptionResolver.class, expectedResolvers.get(2).getClass());
ExceptionHandlerExceptionResolver eher = (ExceptionHandlerExceptionResolver) expectedResolvers.get(0);
assertNotNull(eher.getApplicationContext());
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(eher);
List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyAdvice");
assertEquals(1, interceptors.size());
assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass());
LocaleContextHolder.setLocale(Locale.ENGLISH);
try {
ResponseStatusExceptionResolver rser = (ResponseStatusExceptionResolver) expectedResolvers.get(1);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
rser.resolveException(request, response, context.getBean(TestController.class), new UserAlreadyExistsException());
assertEquals("User already exists!", response.getErrorMessage());
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
/**
* 动态添加消息体响应切面
* @param returnValueHandlers 响应处理器列表(需要注入 {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getReturnValueHandlers()})
* @param handlerExceptionResolver 异常处理解析器(需要注入 {@link org.springframework.web.servlet.HandlerExceptionResolver})
* @param responseBodyAdvice ResponseBodyAdvice
*/
public static void addDynamicResponseBodyAdvice(List<HandlerMethodReturnValueHandler> returnValueHandlers, HandlerExceptionResolver handlerExceptionResolver, ResponseBodyAdvice<?> responseBodyAdvice) {
if (CollectionUtils.isEmpty(returnValueHandlers)) {
return;
}
// 下面这行添加不起作用,由于内部构建已经完成
// adapter.setResponseBodyAdvice(Collections.singletonList(responseBodyAdvice));
for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
// 只有AbstractMessageConverterMethodArgumentResolver继承类型(主要是HttpEntityMethodProcessor、RequestResponseBodyMethodProcessor)有Advice Chain
if (returnValueHandler instanceof AbstractMessageConverterMethodArgumentResolver) {
// TODO <mark> 由于使用底层API, 这个advice.responseBodyAdvice属性在未来版本中可能会改
List<Object> advices = ReflectUtil.invokeFieldPath(returnValueHandler, "advice.responseBodyAdvice");
if (CollectionUtils.isEmpty(advices)) {
continue;
}
advices.add(responseBodyAdvice);
}
}
// 动态添加到异常处理(因为源码流程中的异常处理是新加载的HandlerExceptionResolver,与正常响应处理不是同个处理集)
if (handlerExceptionResolver instanceof HandlerExceptionResolverComposite) {
// SpringMVC默认为注册HandlerExceptionResolverComposite的Bean
List<HandlerExceptionResolver> exceptionResolvers = ((HandlerExceptionResolverComposite) handlerExceptionResolver).getExceptionResolvers();
if (CollectionUtils.isEmpty(exceptionResolvers)) {
return;
}
for (HandlerExceptionResolver exceptionResolver : exceptionResolvers) {
if (exceptionResolver instanceof ExceptionHandlerExceptionResolver) {
HandlerMethodReturnValueHandlerComposite returnValueHandlerComposite = ((ExceptionHandlerExceptionResolver) exceptionResolver).getReturnValueHandlers();
if (returnValueHandlerComposite == null) {
return;
}
SpringMvcPolyfill.addDynamicResponseBodyAdvice(returnValueHandlerComposite.getHandlers(), null, responseBodyAdvice);
}
}
}
}
@Test
@SuppressWarnings("unchecked")
public void handlerExceptionResolver() throws Exception {
ApplicationContext context = initContext(WebConfig.class);
HandlerExceptionResolverComposite compositeResolver =
context.getBean("handlerExceptionResolver", HandlerExceptionResolverComposite.class);
assertEquals(0, compositeResolver.getOrder());
List<HandlerExceptionResolver> expectedResolvers = compositeResolver.getExceptionResolvers();
assertEquals(ExceptionHandlerExceptionResolver.class, expectedResolvers.get(0).getClass());
assertEquals(ResponseStatusExceptionResolver.class, expectedResolvers.get(1).getClass());
assertEquals(DefaultHandlerExceptionResolver.class, expectedResolvers.get(2).getClass());
ExceptionHandlerExceptionResolver eher = (ExceptionHandlerExceptionResolver) expectedResolvers.get(0);
assertNotNull(eher.getApplicationContext());
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(eher);
List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyAdvice");
assertEquals(1, interceptors.size());
assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass());
LocaleContextHolder.setLocale(Locale.ENGLISH);
try {
ResponseStatusExceptionResolver rser = (ResponseStatusExceptionResolver) expectedResolvers.get(1);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
rser.resolveException(request, response, context.getBean(TestController.class), new UserAlreadyExistsException());
assertEquals("User already exists!", response.getErrorMessage());
}
finally {
LocaleContextHolder.resetLocaleContext();
}
}
@Test
public void configureExceptionResolvers() throws Exception {
List<WebMvcConfigurer> configurers = new ArrayList<WebMvcConfigurer>();
configurers.add(new WebMvcConfigurerAdapter() {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
});
delegatingConfig.setConfigurers(configurers);
HandlerExceptionResolverComposite composite =
(HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver();
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}
@Bean
public HandlerExceptionResolver sentryExceptionResolver() {
// Exclude specific events https://stackoverflow.com/questions/48914391/avoid-reporting-broken-pipe-errors-to-sentry-in-a-spring-boot-application
return new SentryExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
Throwable rootCause = ex;
while (rootCause.getCause() != null && rootCause.getCause() != rootCause) {
rootCause = rootCause.getCause();
}
if (rootCause.getMessage() == null || (!rootCause.getMessage().contains("Broken pipe")
&& !rootCause.getMessage().contains("Required request body content is missing")
&& !rootCause.getMessage().contains("Required request body is missing")
&& !rootCause.getMessage().contains("Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'")
&& !rootCause.getMessage().contains("Required String parameter "))
) {
super.resolveException(request, response, handler, ex);
}
return null;
}
};
}
/***
* 添加到exceptionResolvers里的HandlerExceptionResolver,会统一由 HandlerExceptionResolverComposite 组合分派
* 实际上如果HandlerExceptionResolver本身是spring bean,dispather会自动扫描检测并添加到handlerExceptionResolvers
*/
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
if(bootWebExceptionResolver!=null){
exceptionResolvers.add(bootWebExceptionResolver);
}
}
@Bean
@ConditionalOnProperty("SENTRY_DSN") // only if environment variable exists
public HandlerExceptionResolver sentryExceptionResolver() {
// Recipe FROM: https://github.com/getsentry/sentry-java/issues/575
Sentry.getStoredClient().addShouldSendEventCallback(event ->
event.getSentryInterfaces().values().stream()
.filter(ExceptionInterface.class::isInstance)
.map(ExceptionInterface.class::cast)
.map(ExceptionInterface::getExceptions)
.flatMap(Collection::stream)
.noneMatch(sentryException ->
Arrays.stream(ignoredExceptions).anyMatch(ignoredException -> sentryException.getExceptionClassName().equals(ignoredException))
));
Sentry.getStoredClient().addBuilderHelper(eventBuilder -> {
HttpServletRequest request = SentryServletRequestListener.getServletRequest();
if (request == null) {
return;
}
eventBuilder.withTag("method", request.getMethod());
eventBuilder.withTag("application", extractApplication(request.getRequestURI()));
eventBuilder.withTag("uri", defaultString(getMatchingPattern(request)));
eventBuilder.withTag("query", defaultString(request.getQueryString()));
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
eventBuilder.withSentryInterface(new UserInterface(null, authentication.getName(),
remoteAddressResolver.getRemoteAddress(request), null), true);
});
log.info("Creating a SentryExceptionResolver as HandlerExceptionResolver - Ignored exceptions: {}", ignoredExceptions);
return new SentryExceptionResolver();
}
@Test
public void configureExceptionResolvers() throws Exception {
List<WebMvcConfigurer> configurers = new ArrayList<>();
configurers.add(new WebMvcConfigurer() {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
});
delegatingConfig.setConfigurers(configurers);
HandlerExceptionResolverComposite composite =
(HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver();
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
/**
* Resolve the exception by iterating over the list of configured exception resolvers.
* The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler,Exception ex) {
if (this.resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;
}
}
}
return null;
}
/**
* We need to override the base method so this "@Bean" will get invoked and ultimately call configureMessageConverters. Otherwise, it doesn't get called.
* This implementation doesn't do anything except call the super method.
*
* @return the RequestMappingHandlerAdapter.
*/
@Bean
@Override
public HandlerExceptionResolver handlerExceptionResolver()
{
return super.handlerExceptionResolver();
}
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
return new HandlerExceptionResolver() {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
return null;
}
};
}
/**
* Returns a {@link HandlerExceptionResolverComposite} containing a list
* of exception resolvers obtained either through
* {@link #configureHandlerExceptionResolvers(List)} or through
* {@link #addDefaultHandlerExceptionResolvers(List)}.
* <p><strong>Note:</strong> This method cannot be made final due to CGLib
* constraints. Rather than overriding it, consider overriding
* {@link #configureHandlerExceptionResolvers(List)}, which allows
* providing a list of resolvers.
*/
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
@Bean
public HandlerExceptionResolver customExceptionHandlerExceptionResolver() {
CustomExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new CustomExceptionHandlerExceptionResolver(
true);
exceptionHandlerExceptionResolver.getErrorResolver()
.add(new ErrorMappingResolver())
.setDefaultErrorResolver(new DefaultErrorResolver());
return exceptionHandlerExceptionResolver;
}
/**
* Set the list of exception resolvers to delegate to.
*/
public void setExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.resolvers = exceptionResolvers;
}
/**
* Return the list of exception resolvers to delegate to.
*/
public List<HandlerExceptionResolver> getExceptionResolvers() {
return (this.resolvers != null ? Collections.unmodifiableList(this.resolvers) : Collections.emptyList());
}
/**
* Return the list of exception resolvers to delegate to.
*/
public List<HandlerExceptionResolver> getExceptionResolvers() {
return Collections.unmodifiableList(resolvers);
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configureHandlerExceptionResolvers(exceptionResolvers);
}
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.extendHandlerExceptionResolvers(exceptionResolvers);
}
}
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
resolvers.add(new ServiceErrorResolver());
}
/**
* Set the HandlerExceptionResolver types to use as a list.
*/
public StandaloneMockMvcBuilder setHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.handlerExceptionResolvers = exceptionResolvers;
return this;
}
@Override
protected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);
}