千家信息网

使用@RestControllerAdvice怎么对异常进行处理

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇文章给大家分享的是有关使用@RestControllerAdvice怎么对异常进行处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
千家信息网最后更新 2026年11月03日使用@RestControllerAdvice怎么对异常进行处理

本篇文章给大家分享的是有关使用@RestControllerAdvice怎么对异常进行处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

从DispatcherServlet入口,如下:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {    if (logger.isDebugEnabled()) {        String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";        logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +                " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");    }    // Keep a snapshot of the request attributes in case of an include,    // to be able to restore the original attributes after the include.    Map attributesSnapshot = null;    if (WebUtils.isIncludeRequest(request)) {        attributesSnapshot = new HashMap();        Enumeration attrNames = request.getAttributeNames();        while (attrNames.hasMoreElements()) {            String attrName = (String) attrNames.nextElement();            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {                attributesSnapshot.put(attrName, request.getAttribute(attrName));            }        }    }    // Make framework objects available to handlers and view objects.    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());    FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);    if (inputFlashMap != null) {        request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));    }    request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());    request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);    try {        //直接看这个方法        doDispatch(request, response);    }    finally {        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {            // Restore the original attribute snapshot, in case of an include.            if (attributesSnapshot != null) {                restoreAttributesAfterInclude(request, attributesSnapshot);            }        }    }}protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {    HttpServletRequest processedRequest = request;    HandlerExecutionChain mappedHandler = null;    boolean multipartRequestParsed = false;    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);    try {        ModelAndView mv = null;        Exception dispatchException = null;        try {            processedRequest = checkMultipart(request);            multipartRequestParsed = (processedRequest != request);            // Determine handler for the current request.            mappedHandler = getHandler(processedRequest);            if (mappedHandler == null || mappedHandler.getHandler() == null) {                noHandlerFound(processedRequest, response);                return;            }            // Determine handler adapter for the current request.            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());            // Process last-modified header, if supported by the handler.            String method = request.getMethod();            boolean isGet = "GET".equals(method);            if (isGet || "HEAD".equals(method)) {                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());                if (logger.isDebugEnabled()) {                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);                }                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {                    return;                }            }            if (!mappedHandler.applyPreHandle(processedRequest, response)) {                return;            }            // Actually invoke the handler.            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());            if (asyncManager.isConcurrentHandlingStarted()) {                return;            }            applyDefaultViewName(processedRequest, mv);            mappedHandler.applyPostHandle(processedRequest, response, mv);        }        catch (Exception ex) {            dispatchException = ex;        }        catch (Throwable err) {            // As of 4.3, we're processing Errors thrown from handler methods as well,            // making them available for @ExceptionHandler methods and other scenarios.            dispatchException = new NestedServletException("Handler dispatch failed", err);        }        //处理结果(里面含异常处理)        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);    }    catch (Exception ex) {        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);    }    catch (Throwable err) {        triggerAfterCompletion(processedRequest, response, mappedHandler,                new NestedServletException("Handler processing failed", err));    }    finally {        if (asyncManager.isConcurrentHandlingStarted()) {            // Instead of postHandle and afterCompletion            if (mappedHandler != null) {                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);            }        }        else {            // Clean up any resources used by a multipart request.            if (multipartRequestParsed) {                cleanupMultipart(processedRequest);            }        }    }}

进入异常处理的地方

进入到resolveException方法,默认解析器有3个,ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver;具体实例化的地方在WebMvcConfigurationSupport#addDefaultHandlerExceptionResolvers方法

protected final void addDefaultHandlerExceptionResolvers(List exceptionResolvers) {    ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver();    exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager());    exceptionHandlerResolver.setMessageConverters(getMessageConverters());    exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers());    exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers());    if (jackson2Present) {        exceptionHandlerResolver.setResponseBodyAdvice(                Collections.>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());}

先看ExceptionHandlerExceptionResolver的处理如下: ExceptionHandlerExceptionResolver初始化的时候,

@Overridepublic void afterPropertiesSet() {    // Do this first, it may add ResponseBodyAdvice beans    initExceptionHandlerAdviceCache();    if (this.argumentResolvers == null) {        List resolvers = getDefaultArgumentResolvers();        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);    }    if (this.returnValueHandlers == null) {        List handlers = getDefaultReturnValueHandlers();        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);    }}

find所有ControllerAdvice Annotion注解的bean(找@ControllerAdvice注解或者其作为meta annotation,可以看下AnnotationUtils#findAnnotation方法),并排序;如果该类实现了ResponseBodyAdvice(可自定义扩展统一response的返回)接口

public ExceptionHandlerMethodResolver(Class handlerType) {    for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {        for (Class exceptionType : detectExceptionMappings(method)) {            addExceptionMapping(exceptionType, method);        }    }}public static final MethodFilter EXCEPTION_HANDLER_METHODS = new MethodFilter() {    @Override    public boolean matches(Method method) {        return (AnnotationUtils.findAnnotation(method, ExceptionHandler.class) != null);    }};

找到标有ExceptionHandler注解的方法,并缓存再exceptionHandlerCache上,然后判断该ControllerAdviceBean是否能应用到该controller上

protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {    Class handlerType = null;    if (handlerMethod != null) {        // Local exception handler methods on the controller class itself.        // To be invoked through the proxy, even in case of an interface-based proxy.        handlerType = handlerMethod.getBeanType();        ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);        if (resolver == null) {            resolver = new ExceptionHandlerMethodResolver(handlerType);            this.exceptionHandlerCache.put(handlerType, resolver);        }        Method method = resolver.resolveMethod(exception);        if (method != null) {            return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);        }        // For advice applicability check below (involving base packages, assignable types        // and annotation presence), use target class instead of interface-based proxy.        if (Proxy.isProxyClass(handlerType)) {            handlerType = AopUtils.getTargetClass(handlerMethod.getBean());        }    }    for (Map.Entry entry : this.exceptionHandlerAdviceCache.entrySet()) {        ControllerAdviceBean advice = entry.getKey();        //判断是否匹配        if (advice.isApplicableToBeanType(handlerType)) {            ExceptionHandlerMethodResolver resolver = entry.getValue();            Method method = resolver.resolveMethod(exception);            if (method != null) {                return new ServletInvocableHandlerMethod(advice.resolveBean(), method);            }        }    }    return null;}

可以看一下ControllerAdvice注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface ControllerAdvice {/** * Alias for the {@link #basePackages} attribute. * 

Allows for more concise annotation declarations e.g.: * {@code @ControllerAdvice("org.my.pkg")} is equivalent to * {@code @ControllerAdvice(basePackages="org.my.pkg")}. * @since 4.0 * @see #basePackages() */@AliasFor("basePackages")String[] value() default {};/** * Array of base packages. *

Controllers that belong to those base packages or sub-packages thereof * will be included, e.g.: {@code @ControllerAdvice(basePackages="org.my.pkg")} * or {@code @ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"})}. *

{@link #value} is an alias for this attribute, simply allowing for * more concise use of the annotation. *

Also consider using {@link #basePackageClasses()} as a type-safe * alternative to String-based package names. * @since 4.0 */@AliasFor("value")String[] basePackages() default {};/** * Type-safe alternative to {@link #value()} for specifying the packages * to select Controllers to be assisted by the {@code @ControllerAdvice} * annotated class. *

Consider creating a special no-op marker class or interface in each package * that serves no purpose other than being referenced by this attribute. * @since 4.0 */Class[] basePackageClasses() default {};/** * Array of classes. *

Controllers that are assignable to at least one of the given types * will be assisted by the {@code @ControllerAdvice} annotated class. * @since 4.0 */Class[] assignableTypes() default {};/** * Array of annotations. *

Controllers that are annotated with this/one of those annotation(s) * will be assisted by the {@code @ControllerAdvice} annotated class. *

Consider creating a special annotation or use a predefined one, * like {@link RestController @RestController}. * @since 4.0 */Class[] annotations() default {};}

最后,定位到ServletInvocableHandlerMethod#invokeAndHandle异常方法处理 RequestResponseBodyMethodProcessor#handleReturnValue 通过消息解析器,把流写出去

protected  void writeWithMessageConverters(T value, MethodParameter returnType,        ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)        throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {    Object outputValue;    Class valueType;    Type declaredType;    if (value instanceof CharSequence) {        outputValue = value.toString();        valueType = String.class;        declaredType = String.class;    }    else {        outputValue = value;        valueType = getReturnValueType(outputValue, returnType);        declaredType = getGenericType(returnType);    }    HttpServletRequest request = inputMessage.getServletRequest();    List requestedMediaTypes = getAcceptableMediaTypes(request);    List producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);    if (outputValue != null && producibleMediaTypes.isEmpty()) {        throw new IllegalArgumentException("No converter found for return value of type: " + valueType);    }    Set compatibleMediaTypes = new LinkedHashSet();    for (MediaType requestedType : requestedMediaTypes) {        for (MediaType producibleType : producibleMediaTypes) {            if (requestedType.isCompatibleWith(producibleType)) {                compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));            }        }    }    if (compatibleMediaTypes.isEmpty()) {        if (outputValue != null) {            throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);        }        return;    }    List mediaTypes = new ArrayList(compatibleMediaTypes);    MediaType.sortBySpecificityAndQuality(mediaTypes);    MediaType selectedMediaType = null;    for (MediaType mediaType : mediaTypes) {        if (mediaType.isConcrete()) {            selectedMediaType = mediaType;            break;        }        else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {            selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;            break;        }    }    if (selectedMediaType != null) {        selectedMediaType = selectedMediaType.removeQualityValue();        for (HttpMessageConverter messageConverter : this.messageConverters) {            if (messageConverter instanceof GenericHttpMessageConverter) {                if (((GenericHttpMessageConverter) messageConverter).canWrite(                        declaredType, valueType, selectedMediaType)) {                    outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,                            (Class>) messageConverter.getClass(),                            inputMessage, outputMessage);                    if (outputValue != null) {                        addContentDispositionHeader(inputMessage, outputMessage);                        ((GenericHttpMessageConverter) messageConverter).write(                                outputValue, declaredType, selectedMediaType, outputMessage);                        if (logger.isDebugEnabled()) {                            logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +                                    "\" using [" + messageConverter + "]");                        }                    }                    return;                }            }            else if (messageConverter.canWrite(valueType, selectedMediaType)) {                outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,                        (Class>) messageConverter.getClass(),                        inputMessage, outputMessage);                if (outputValue != null) {                    addContentDispositionHeader(inputMessage, outputMessage);                    ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);                    if (logger.isDebugEnabled()) {                        logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +                                "\" using [" + messageConverter + "]");                    }                }                return;            }        }    }    if (outputValue != null) {        throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);    }}

在body writer之前,会先调用ResponseBodyAdvice match做一层处理,也就是说,

@RestControllerAdvicepublic class GlobalExceptionHandler extends ResponseEntityExceptionHandler implements ResponseBodyAdvice {}

以上就是使用@RestControllerAdvice怎么对异常进行处理,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

处理 方法 注解 地方 更多 知识 篇文章 e.g. 实用 也就是 也就是说 入口 实例 就是 工作会 接口 文章 时候 消息 看吧 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司起名 重生之互联网科技帝国 中国互联网科技股 互联网 科技 互联网科技公司官网 未来的互联网科技 苏州互联网科技贷款公司 中盈科技互联网信息有限公司 荆州市昕露互联网络科技有限公司 互联网保险科技创业 互联网数据科技专业 互联网科技如何创业 卓翼科技产业互联网合作 山东子淼互联网科技有限公司 互联网公司高科技产品 云鲸互联网络科技有限公司 中国科技和美国互联网 长沙易易互联网科技有限公司 广东猫王互联网科技有限公司电话 科技美学互联网 艺术 互联网金融 金融科技 以房互联网科技 顺玮阁互联网科技 哈尔滨新华互联网科技 成都仁贤领冠互联网科技有限公司 互联网企业和科技型企业 互联网在线教育科技创业 广州富喜互联网络科技 互联网金融运营模式中的金融科技 银川新华互联网科技学校原画
0