这篇文章主要介绍了SpringFramework之ControllerAdvice注解怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。
站在用户的角度思考问题,与客户深入沟通,找到汤阴网站设计与汤阴网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:网站设计、成都网站设计、企业官网、英文网站、手机端网站、网站推广、空间域名、雅安服务器托管、企业邮箱。业务覆盖汤阴地区。
SpringFramework版本5.0.9.release。
我们会通过@ControllerAdvice和@ExceptionHandler来处理异常,Springmvc是如何进行处理的呢?
ControllerAdviceBean有个重要的方法findAnnotatedBeans,如下List-1
List-1
public class ControllerAdviceBean implements Ordered {
    ...
    public static List findAnnotatedBeans(ApplicationContext applicationContext) {
        List beans = new ArrayList();
        String[] var2 = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class);
        int var3 = var2.length;
        for(int var4 = 0; var4 < var3; ++var4) {
            String name = var2[var4];
            if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) {
                beans.add(new ControllerAdviceBean(name, applicationContext));
            }
        }
        return beans;
    }
    ...  如List-1所示,从applicationContext中获取所有的ControllerAdvice注解的Bean,之后封装到ControllerAdviceBean中。
来看下ExceptionHandlerExceptionResolver,它的类继承图如下图1所示:
       
图1
ExceptionHandlerExceptionResolver是HandlerExceptionResolver,所以在Springmvc的doDispatch中会调用它。实现了InitializingBean,所以有afterPropertiesSet方法,如下List-2所示:
List-2
@Override
public void afterPropertiesSet() {
    // Do this first, it may add ResponseBodyAdvice beans
    initExceptionHandlerAdviceCache();
    ...
}
private void initExceptionHandlerAdviceCache() {
    ...
    List adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
    AnnotationAwareOrderComparator.sort(adviceBeans);
    for (ControllerAdviceBean adviceBean : adviceBeans) {
        Class> beanType = adviceBean.getBeanType();
        if (beanType == null) {
            throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
        }
        ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
        if (resolver.hasExceptionMappings()) {
            this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
            if (logger.isInfoEnabled()) {
                logger.info("Detected @ExceptionHandler methods in " + adviceBean);
            }
        }
        if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
            this.responseBodyAdvice.add(adviceBean);
            if (logger.isInfoEnabled()) {
                logger.info("Detected ResponseBodyAdvice implementation in " + adviceBean);
            }
        }
    }
} List-2中,initExceptionHandlerAdviceCache方法调用List-1中ControllerAdviceBean的findAnnotatedBeans方法,获取所有ControllerAdvice的bean,之后排序,所以当有多个ControllerAdivce注解的类且需要排序时,可以实现spring的Order接口来实现。
之后遍历ControllerAdviceBean,之后获取Bean的class类,传入到ExceptionHandlerMethodResolver的构造方法中,如下List-3所示:
List-3
public class ExceptionHandlerMethodResolver {
    ...
	public static final MethodFilter EXCEPTION_HANDLER_METHODS = method ->
			(AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null);
    ...
	private final Map, Method> mappedMethods = new HashMap<>(16);
    ...
	public ExceptionHandlerMethodResolver(Class> handlerType) {
		for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
			for (Class extends Throwable> exceptionType : detectExceptionMappings(method)) {
				addExceptionMapping(exceptionType, method);
			}
		}
    }
    ...
	private List> detectExceptionMappings(Method method) {
		List> result = new ArrayList<>();
		detectAnnotationExceptionMappings(method, result);
		if (result.isEmpty()) {
			for (Class> paramType : method.getParameterTypes()) {
				if (Throwable.class.isAssignableFrom(paramType)) {
					result.add((Class extends Throwable>) paramType);
				}
			}
		}
		if (result.isEmpty()) {
			throw new IllegalStateException("No exception types mapped to " + method);
		}
		return result;
	}
	protected void detectAnnotationExceptionMappings(Method method, List> result) {
		ExceptionHandler ann = AnnotationUtils.findAnnotation(method, ExceptionHandler.class);
		Assert.state(ann != null, "No ExceptionHandler annotation");
		result.addAll(Arrays.asList(ann.value()));
	}
	private void addExceptionMapping(Class extends Throwable> exceptionType, Method method) {
		Method oldMethod = this.mappedMethods.put(exceptionType, method);
		if (oldMethod != null && !oldMethod.equals(method)) {
			throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" +
					exceptionType + "]: {" + oldMethod + ", " + method + "}");
		}
	}    - 找到方法上有ExceptionHandler注解的方法。 
- detectExceptionMappings方法获取ExceptionHandler的value值,如果我们没有设置ExceptionHandler的value,那么遍历方法的参数,如果参数是Throwable的子类,就将改类型放入result中,所以由此可知道,我们可以不设置ExceptionHandler的value,只需要将方法的参数设置为Throwable的子类即可,spring会自动识别。 
- addExceptionMapping方法将结果放入mappedMethods这个map中,key是Throwable,而value则是method。 
再回到List-2中,initExceptionHandlerAdviceCache方法中,将构造好的ControllerAdviceBean和ExceptionHandlerMethodResolver放入到exceptionHandlerAdviceCache(是个map)中。
HandlerExceptionResolver是个接口,如下List-4所示:
List-4
public interface HandlerExceptionResolver {
	@Nullable
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
}AbstractHandlerExceptionResolver.resolveException->AbstractHandlerMethodExceptionResolver.doResolveException->ExceptionHandlerExceptionResolver.doResolveHandlerMethodException。
接下来,来看Springmvc中是如何处理我们的ControllerAdvice的。
DispatcherServlet中,doDispatch()->processDispatchResult()->processHandlerException(),如下List-5所示,会遍历HandlerExceptionResovler来处理。
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
    ModelAndView exMv = null;
    if (this.handlerExceptionResolvers != null) {
    for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
        exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
        if (exMv != null) {
            break;
        }
    }
}ExceptionHandlerExceptionResolver是如何加入到Springmvc中handlerExceptionResolvers的,是因为DispatcherServlet.properties中HandlerExceptionResolver的值有ExceptionHandlerExceptionResolver,所以会被Spring自动加入进去。
Spring通过上面的方式,将捕获到的异常交给ExceptionHandlerExceptionResolver.doResolveHandlerMethodException来处理,通过多次转换,最终调用我们设置带有ExceptionHandler注解的方法。
通过源码分析,带有ControllerAdvice和ExceptionHandler注解的拦截处理的执行先于HandlerInterceptor的afterCompletion。
感谢你能够认真阅读完这篇文章,希望小编分享的“SpringFramework之ControllerAdvice注解怎么用”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!
当前标题:SpringFramework之ControllerAdvice注解怎么用
地址分享:http://www.scyingshan.cn/article/jegspo.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 