相关文章推荐
虚心的长颈鹿  ·  django rest framework ...·  2 周前    · 
幸福的梨子  ·  Azure Database for ...·  1 月前    · 
细心的乒乓球  ·  Outlook 日历 REST API ...·  1 月前    · 
纯真的橙子  ·  System.Threading.Timer ...·  1 年前    · 
强健的吐司  ·  sqlite 批量insert-掘金·  1 年前    · 

1.先看异常是不是@ExceptionHandler中配置的
2.异常可能提示的是A异常,实际上捕捉的B异常,例如JsonParseExcepetion被捕捉,抛出的是HttpMessageNotReadableException异常

源码解析:
AbstractHandlerExceptionResolver中调用resolveException方法

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (!this.shouldApplyTo(request, handler)) {
            return null;
        } else {
            this.prepareResponse(ex, response);
            ModelAndView result = this.doResolveException(request, response, handler, ex);
            if (result != null) {
                if (this.logger.isWarnEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
                    this.logger.warn("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
                this.logException(ex, request);
            return result;

接下来调用
ExceptionHandlerExceptionResolver的doResolveHandlerMethodException方法

	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
		ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
		if (exceptionHandlerMethod == null) {
			return null;
		exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		try {
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
			Throwable cause = exception.getCause();
			if (cause != null) {
				// Expose cause as provided argument as well
				exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
			else {
				// Otherwise, just the given exception as-is
				exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, handlerMethod);
		catch (Throwable invocationEx) {
			// Any other than the original exception is unintended here,
			// probably an accident (e.g. failed assertion or the like).
			if (invocationEx != exception && logger.isWarnEnabled()) {
				logger.warn("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
			// Continue with default processing of the original exception...
			return null;
		if (mavContainer.isRequestHandled()) {
			return new ModelAndView();
		else {
			ModelMap model = mavContainer.getModel();
			HttpStatus status = mavContainer.getStatus();
			ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status);
			mav.setViewName(mavContainer.getViewName());
			if (!mavContainer.isViewReference()) {
				mav.setView((View) mavContainer.getView());
			if (model instanceof RedirectAttributes) {
				Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			return mav;

重点重点!!!!
之后调用ExceptionHandlerMethodResolver方法

	public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
		Method method = this.exceptionLookupCache.get(exceptionType);
		if (method == null) {
			method = getMappedMethod(exceptionType);
			this.exceptionLookupCache.put(exceptionType, (method != null ? method : NO_METHOD_FOUND));
		return (method != NO_METHOD_FOUND ? method : null);

上述方法之后有cache记录了每次的异常信息
只有系统启动后第一次controller层遇到了异常,才会走getMappedMethod方法:

	private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
		List<Class<? extends Throwable>> matches = new ArrayList<Class<? extends Throwable>>();
		for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
			if (mappedException.isAssignableFrom(exceptionType)) {
				matches.add(mappedException);
		if (!matches.isEmpty()) {
			Collections.sort(matches, new ExceptionDepthComparator(exceptionType));
			return this.mappedMethods.get(matches.get(0));
		else {
			return null;

上述方法调用了ExceptionDepthComparator,将接近异常的从深度小到大进行排序,返回最接近的父类异常再进入对应的ExceptionHandler

自己测试的时候一直都没进入getMappedMethod方法,一步一步debug才发现。

1.先看异常是不是@ExceptionHandler中配置的2.异常可能提示的是A异常,实际上捕捉的B异常,例如JsonParseExcepetion被捕捉,抛出的是HttpMessageNotReadableException异常源码解析:AbstractHandlerExceptionResolver中调用resolveException方法 public ModelAndView resolveException(HttpServletRequest request, HttpServl 1、使用aop进行切面拦截异常 2、controller每个方法都用try-catch捕获异常 3、增加一个@RestControllerAdvice标注的类,负责处理我们项目的异常 一般放在一个类就不会有这种情况了,而我用了两个类全局异常处理类和接口参数校验处理类 还有一种情况是一用力别人的模块,模块是用了@RestControllerAdvice的类, 多个加了@RestControllerAdvice的类它们会按照类名依次加载,如果前面的类有能处 1、Spring 的 @ExceptionHandler 注解用于统一处理控制层(Ctroller)往外抛的异常。 @ExceptionHandler 注解标注在方法上,此方法会统一处理同一 Controller 下其它 @RequestMapping 注解标注的方法抛出的异常 @ExceptionHandler 注解的属性的 value 值是一个 Class 类型的数组,表示处理哪些类型的异常,为空时表示处理所有异常。 @Excep... 2个服务:A-common 和 BService,各自有异常处理器。 其A定义了通用的异常处理器,供所有服务直接调用。 但是B服务由于业务需求需要处理一些A没有的异常,由于A存在兜底逻辑:对Exception进行捕获,这个时候就要指定异常处理器的执行顺序Spring的异常处理器是根据异常处理器被加载的顺序来顺序执行,比如:A->B->C ,如果B拦截并且处理了某个异常,就会直接抛出,C的异常处理器就执行不到了。 可以通过 @Order 注解来 pulbic classExceptionControllerAdvice{   @ExceptionHandler(NotFoundException.class)   @ResponseB...
是一个组合注解,由、组成,而继承了@Component,因此本质上是个,用于定义,和方法,适用于所有使用方法。 @ControllerAdvice可以指定 Controller 范围 basePackageClasses: 是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理 assignableTypes: 指定一个或多个 Controller 类,这些类被该 @C
@RestControllerAdvice是一个注解,用于定义全局异常处理和全局数据绑定的类。它可以被应用于带有@Controller或@RestController注解的类上,用于统一处理这些类抛出的异常,并对返回的数据进行统一处理。@RestControllerAdvice主要有以下几个作用: 1. 全局异常处理:通过在@RestControllerAdvice定义处理方法,可以统一处理应用程序抛出的异常。这些异常处理方法使用@ExceptionHandler注解进行标注,并指定要处理的异常类型。当应用程序发生指定类型的异常时,会自动调用相应的异常处理方法,并返回处理后的结果给客户端。 2. 全局数据绑定:通过在@RestControllerAdvice定义@InitBinder注解的方法,可以统一处理请求参数的数据绑定。这些方法使用@InitBinder注解进行标注,并指定要处理的参数类型。在处理请求时,Spring会自动调用相应的数据绑定方法,进行请求参数的数据绑定操作。 3. 全局数据预处理:通过在@RestControllerAdvice定义@ModelAttribute注解的方法,可以在处理请求之前对数据进行预处理。这些方法使用@ModelAttribute注解进行标注,并指定要处理的参数类型。在处理请求时,Spring会自动调用相应的数据预处理方法,对请求数据进行处理。 综上所述,@RestControllerAdvice的作用是实现全局异常处理、全局数据绑定和全局数据预处理。