RequestBodyAdvice和ResponseBodyAdvice原理详解

计算机毕设项目源码获取:

📢链接点击直达:Java 项目合作-CSDN博客


一、源码解析

这是spring 4.2新加的两个接口

1、RequestBodyAdvice类

public interface RequestBodyAdvice {

   boolean supports(MethodParameter methodParameter, Type targetType,
         Class<? extends HttpMessageConverter<?>> converterType);

   HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
         Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;
   Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
         Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
   @Nullable
   Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
         Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
}

查看一下谁调用了这个接口的这些方法,可以看到AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters()方法调用了这个接口的方法。

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
      Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

   MediaType contentType;
   boolean noContentType = false;
   try {
      contentType = inputMessage.getHeaders().getContentType();
   }
   catch (InvalidMediaTypeException ex) {
      throw new HttpMediaTypeNotSupportedException(ex.getMessage());
   }
   if (contentType == null) {
      noContentType = true;
      contentType = MediaType.APPLICATION_OCTET_STREAM;
   }

   Class<?> contextClass = parameter.getContainingClass();
   Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
   if (targetClass == null) {
      ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
      targetClass = (Class<T>) resolvableType.resolve();
   }

   HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
   Object body = NO_VALUE;

   EmptyBodyCheckingHttpInputMessage message = null;
   try {
      message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

      for (HttpMessageConverter<?> converter : this.messageConverters) {
         Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
         GenericHttpMessageConverter<?> genericConverter =
               (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
         if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
               (targetClass != null && converter.canRead(targetClass, contentType))) {
            if (message.hasBody()) {
                "RequestBodyAdvice方法调用"
               HttpInputMessage msgToUse =
                     getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
               body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                     ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
               body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
            }
            else {
               body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
            }
            break;
         }
      }
   }
   catch (IOException ex) {
      throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
   }
   finally {
      if (message != null && message.hasBody()) {
         closeStreamIfNecessary(message.getBody());
      }
   }

   if (body == NO_VALUE) {
      if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
            (noContentType && !message.hasBody())) {
         return null;
      }
      throw new HttpMediaTypeNotSupportedException(contentType,
            getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));
   }

   MediaType selectedContentType = contentType;
   Object theBody = body;
   LogFormatUtils.traceDebug(logger, traceOn -> {
      String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
      return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
   });

   return body;
}
// 
private final RequestResponseBodyAdviceChain advice;
RequestResponseBodyAdviceChain getAdvice() {
   return this.advice;
}

可以看到这接口的方法,主要是在HttpMessageConverter处理request body的前后做一些处理和body为空的时候做处理。

从这个可以看出,我们可以在使用这些HandlerMethodArgumentResolver的时候,我们能对request body进行前处理和解析后处理。

2、ResponseBodyAdvice类

ublic interface ResponseBodyAdvice<T> {

   boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);

   @Nullable
   T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
         Class<? extends HttpMessageConverter<?>> selectedConverterType,
         ServerHttpRequest request, ServerHttpResponse response);

}

调用解析:

AbstractMessageConverterMethodProcessor.class

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
      ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
      throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

   Object body;
   Class<?> valueType;
   Type targetType;

   if (value instanceof CharSequence) {
      body = value.toString();
      valueType = String.class;
      targetType = String.class;
   }
   else {
      body = value;
      valueType = getReturnValueType(body, returnType);
      targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
   }

   if (isResourceType(value, returnType)) {
      outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
      if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
            outputMessage.getServletResponse().getStatus() == 200) {
         Resource resource = (Resource) value;
         try {
            List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
            outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
            body = HttpRange.toResourceRegions(httpRanges, resource);
            valueType = body.getClass();
            targetType = RESOURCE_REGION_LIST_TYPE;
         }
         catch (IllegalArgumentException ex) {
            outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
            outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
         }
      }
   }

   MediaType selectedMediaType = null;
   MediaType contentType = outputMessage.getHeaders().getContentType();
   boolean isContentTypePreset = contentType != null && contentType.isConcrete();
   if (isContentTypePreset) {
      if (logger.isDebugEnabled()) {
         logger.debug("Found 'Content-Type:" + contentType + "' in response");
      }
      selectedMediaType = contentType;
   }
   else {
      HttpServletRequest request = inputMessage.getServletRequest();
      // 处理请求协商类型
      List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
      List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);

      if (body != null && producibleTypes.isEmpty()) {
         throw new HttpMessageNotWritableException(
               "No converter found for return value of type: " + valueType);
      }
      List<MediaType> mediaTypesToUse = new ArrayList<>();
      for (MediaType requestedType : acceptableTypes) {
         for (MediaType producibleType : producibleTypes) {
            if (requestedType.isCompatibleWith(producibleType)) {
               mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
            }
         }
      }
      if (mediaTypesToUse.isEmpty()) {
         if (body != null) {
            throw new HttpMediaTypeNotAcceptableException(producibleTypes);
         }
         if (logger.isDebugEnabled()) {
            logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
         }
         return;
      }

      MediaType.sortBySpecificityAndQuality(mediaTypesToUse);

      for (MediaType mediaType : mediaTypesToUse) {
         if (mediaType.isConcrete()) {
            selectedMediaType = mediaType;
            break;
         }
         else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
            selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
            break;
         }
      }

      if (logger.isDebugEnabled()) {
         logger.debug("Using '" + selectedMediaType + "', given " +
               acceptableTypes + " and supported " + producibleTypes);
      }
   }

   if (selectedMediaType != null) {
      selectedMediaType = selectedMediaType.removeQualityValue();
      for (HttpMessageConverter<?> converter : this.messageConverters) {
         GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
               (GenericHttpMessageConverter<?>) converter : null);
         if (genericConverter != null ?
               ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
               converter.canWrite(valueType, selectedMediaType)) {
                   // 调用ResponseBodyAdvice
            body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                  (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                  inputMessage, outputMessage);
            if (body != null) {
               Object theBody = body;
               LogFormatUtils.traceDebug(logger, traceOn ->
                     "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
               addContentDispositionHeader(inputMessage, outputMessage);
               if (genericConverter != null) {
                  genericConverter.write(body, targetType, selectedMediaType, outputMessage);
               }
               else {
                  ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
               }
            }
            else {
               if (logger.isDebugEnabled()) {
                  logger.debug("Nothing to write: null body");
               }
            }
            return;
         }
      }
   }

   if (body != null) {
      Set<MediaType> producibleMediaTypes =
            (Set<MediaType>) inputMessage.getServletRequest()
                  .getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

      if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {
         throw new HttpMessageNotWritableException(
               "No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");
      }
      throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
   }
}

此可以对@ResponseBody的返回结果在输出到响应之前做处理。通过泛型,指定需要被“拦截”的响应体对象类型。该接口的实现会在 Controller 方法返回数据,并且匹配到了 HttpMessageConverter 之后,HttpMessageConverter 进行序列化之前执行。可以通过覆写 beforeBodyWrite 来统一的对响应体进行修改。

二、为什么说要加上@ControllerAdvice注解,且实现RequestBodyAdvice或ResponseBodyAdvice接口

现在来分析为什么需要实现RequestBodyAdvice接口的同时要加上ControllerAdvice注解。

1、为什么要实现RequestBodyAdvice或ResponseBodyAdvice接口?简单来说,要想执行afterBodyRead方法,必须实现ResponseBodyAdvice接口。RequestResponseBodyAdviceChain的afterBodyRead方法:调用getMatchingAdvice方法,获取RequestBodyAdvice类型的advice其中:class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyAdvice

public HttpInputMessage beforeBodyRead(HttpInputMessage request, MethodParameter parameter,
      Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
// 此advice就是我们定义的类
   for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {
      //如果supports方法的返回值为true,则执行RequestBodyAdvice的afterBodyRead方法
      if (advice.supports(parameter, targetType, converterType)) {
         request = advice.beforeBodyRead(request, parameter, targetType, converterType);
      }
   }
   return request;
}

getMatchAdvice:获取RequestBodyAdvice类型的advice(此advice是我们定义的),如果不是RequestBodyAdvice类型就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因

private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) {
  ;//获取RequestBodyAdvice类型的advice(此advice是我们定义实现RequestBodyAdvice接口的类)
    List<Object> availableAdvice = getAdvice(adviceType);
   if (CollectionUtils.isEmpty(availableAdvice)) {
      return Collections.emptyList();
   }
   List<A> result = new ArrayList<>(availableAdvice.size());
   for (Object advice : availableAdvice) {
      if (advice instanceof ControllerAdviceBean) {
         ControllerAdviceBean adviceBean = (ControllerAdviceBean) advice;
         if (!adviceBean.isApplicableToBeanType(parameter.getContainingClass())) {
            continue;
         }
         // 返回的是我们定义的Advice,即根据Bean的名称从BeanFactory中获取Bean对象
         advice = adviceBean.resolveBean();
      }
      // 判断这个类是否是RequestBodyAdvice类型,如果不是就不会加到结果集,所以这就是我们实现RequestBodyAdvice的原因
      if (adviceType.isAssignableFrom(advice.getClass())) {
         result.add((A) advice);
      }
   }
   return result;
}

getAdvice方法:

private List<Object> getAdvice(Class<?> adviceType) {
        if (RequestBodyAdvice.class == adviceType) {
            return this.requestBodyAdvice;
        } else if (ResponseBodyAdvice.class == adviceType) {
            return this.responseBodyAdvice;
        } else {
            throw new IllegalArgumentException("Unexpected adviceType: " + adviceType);
        }
    }

resolveBean方法:this.beanOrName是string类型的,从beanFactory中再拿到对应的bean对象。

public Object resolveBean() {
        if (this.resolvedBean == null) {
            Object resolvedBean = this.obtainBeanFactory().getBean((String)this.beanOrName); // obtainBeanFactory()返回BeanFactory对象
            if (!this.isSingleton) {
                return resolvedBean;
            }

            this.resolvedBean = resolvedBean;
        }

        return this.resolvedBean;
    }

2、为什么要加上@ControllerAdvice注解?简单说,只有加上@ControllerAdvice,才能找到ControllerAdviceBean。HandlerAdapter字面上的意思就是处理适配器,它的作用用一句话概括就是调用具体的方法对用户发来的请求来进行处理。当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据controller对应的controller类型来调用相应的HandlerAdapter来进行处理。

RequestMappingHandlerAdapter就比较复杂了,可以说,该类是整个SpringMVC中最复杂的类了,却也是目前SpringMVC中使用到的频率最高的类。目前在SpringMVC的使用过程中,对请求的处理主要就是依赖RequestMappingHandlerMapping和RequestMappingHandlerAdapter类的配合使用。下面重点介绍下RequestMappingHandlerAdapter类

RequestMappingHandlerAdapter初始化流程:

RequestMappingHandlerAdapter实现了InitializingBean接口,Spring容器会自动调用其afterPropertiesSet方法。

public void afterPropertiesSet() {
        this.initControllerAdviceCache();  // 获取ControllerAdviceBean的集合
        List handlers;
        if (this.argumentResolvers == null) {
        "把获取的ControllerAdviceBean集合赋值到调用的对象中,调用RequestBodyAdvice的地方"        
            handlers = this.getDefaultArgumentResolvers();
            this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.initBinderArgumentResolvers == null) {
            handlers = this.getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.returnValueHandlers == null) {
        "把获取的ControllerAdviceBean集合赋值到调用的对象中,调用ResponseBodyAdvice的地方"   
            handlers = this.getDefaultReturnValueHandlers();
            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
        }

    }
  • argumentResolvers:用于给处理器方法设置参数
  • initBinderArgumentResolvers:用于给注释了@InitBinder方法设置参数
  • returnValueHandlers:用于对处理器返回值进行相应处理

(1) 获取@ControllerAdvice注解的类封装为ControllerAdviceBean的集合,遍历ControllerAdviceBean集合

提取没有@RequestMapping注解标注的,但有@ModelAttribute注解标注的方法

提取@InitBinder注解标注的方法

提取实现了RequestBodyAdvice或ResponseBodyAdvice接口的类

(2) 没有设置argumentResolvers则获取默认的HandlerMethodArgumentResolver

(3) 没有设置initBinderArgumentResolvers则获取默认的处理参数绑定的HandlerMethodArgumentResolver

(4) 没有设置returnValueHandlers则获取默认的HandlerMethodReturnValueHandler

RequestMappingHandlerAdapter的getDefaultReturnValueHandlers方法:初始化了RequestResponseBodyMethodProcessor

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
   List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
   // Annotation-based argument resolution
   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
   resolvers.add(new RequestParamMapMethodArgumentResolver());
   resolvers.add(new PathVariableMethodArgumentResolver());
   resolvers.add(new PathVariableMapMethodArgumentResolver());
   resolvers.add(new MatrixVariableMethodArgumentResolver());
   resolvers.add(new MatrixVariableMapMethodArgumentResolver());
   resolvers.add(new ServletModelAttributeMethodProcessor(false));
   // requestResponseBodyAdvice 赋值
   resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
   resolvers.add(new RequestHeaderMapMethodArgumentResolver());
   resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
   resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
   resolvers.add(new SessionAttributeMethodArgumentResolver());
   resolvers.add(new RequestAttributeMethodArgumentResolver());
   // Type-based argument resolution
   resolvers.add(new ServletRequestMethodArgumentResolver());
   resolvers.add(new ServletResponseMethodArgumentResolver());
   resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RedirectAttributesMethodArgumentResolver());
   resolvers.add(new ModelMethodProcessor());
   resolvers.add(new MapMethodProcessor());
   resolvers.add(new ErrorsMethodArgumentResolver());
   resolvers.add(new SessionStatusMethodArgumentResolver());
   resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
   if (KotlinDetector.isKotlinPresent()) {
      resolvers.add(new ContinuationHandlerMethodArgumentResolver());
   }
   // Custom arguments
   if (getCustomArgumentResolvers() != null) {
      resolvers.addAll(getCustomArgumentResolvers());
   }
   // Catch-all
   resolvers.add(new PrincipalMethodArgumentResolver());
   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
   resolvers.add(new ServletModelAttributeMethodProcessor(true));
   return resolvers;
}

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
   List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);
   // Single-purpose return value types
   handlers.add(new ModelAndViewMethodReturnValueHandler());
   handlers.add(new ModelMethodProcessor());
   handlers.add(new ViewMethodReturnValueHandler());
   handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
         this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
   handlers.add(new StreamingResponseBodyReturnValueHandler());
   // requestResponseBodyAdvice赋值
   handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
         this.contentNegotiationManager, this.requestResponseBodyAdvice));
   handlers.add(new HttpHeadersReturnValueHandler());
   handlers.add(new CallableMethodReturnValueHandler());
   handlers.add(new DeferredResultMethodReturnValueHandler());
   handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));

   // Annotation-based return value types
   handlers.add(new ServletModelAttributeMethodProcessor(false));
   // requestResponseBodyAdvice赋值
   handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
         this.contentNegotiationManager, this.requestResponseBodyAdvice));
   // Multi-purpose return value types
   handlers.add(new ViewNameMethodReturnValueHandler());
   handlers.add(new MapMethodProcessor());
   // Custom return value types
   if (getCustomReturnValueHandlers() != null) {
      handlers.addAll(getCustomReturnValueHandlers());
   }
   // Catch-all
   if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
      handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
   }
   else {
      handlers.add(new ServletModelAttributeMethodProcessor(true));
   }
   return handlers;
}

requestResponseBodyAdvice:用来保存实现了RequestBodyAdvice或ResponseBodyAdvice接口的类

RequestMappingHandlerAdapter类的initControllerAdviceCache方法:初始化List集合requestResponseBodyAdvice

private void initControllerAdviceCache() {
   if (getApplicationContext() == null) {
      return;
   }
   // 获取有@ControllerAdvice注解的Bean的集合
   List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

   List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

   for (ControllerAdviceBean adviceBean : adviceBeans) {
      Class<?> beanType = adviceBean.getBeanType();
      if (beanType == null) {
         throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
      }
      Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
      if (!attrMethods.isEmpty()) {
         this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
      }
      Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
      if (!binderMethods.isEmpty()) {
         this.initBinderAdviceCache.put(adviceBean, binderMethods);
      }
      if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
         requestResponseBodyAdviceBeans.add(adviceBean); // 将ControllerAdviceBean放入List集合中
      }
   }

   if (!requestResponseBodyAdviceBeans.isEmpty()) {
       // 将存有ControllerAdviceBean的集合存入requestResponseBodyAdvice集合中
      this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
   }

   if (logger.isDebugEnabled()) {
      int modelSize = this.modelAttributeAdviceCache.size();
      int binderSize = this.initBinderAdviceCache.size();
      int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
      int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
      if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
         logger.debug("ControllerAdvice beans: none");
      }
      else {
         logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
               " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
      }
   }
}

ControllerAdviceBean(有@ControllerAdvice注解的Bean)的findAnnotatedBeans方法:获得所有的ControllerAdvice类,之后封装为ControllerAdviceBean

public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
   List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
   for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class)) {
      if (!ScopedProxyUtils.isScopedTarget(name)) {
         ControllerAdvice controllerAdvice = context.findAnnotationOnBean(name, ControllerAdvice.class);
         if (controllerAdvice != null) {
            // Use the @ControllerAdvice annotation found by findAnnotationOnBean()
            // in order to avoid a subsequent lookup of the same annotation.
            adviceBeans.add(new ControllerAdviceBean(name, context, controllerAdvice));
         }
      }
   }
   OrderComparator.sort(adviceBeans);
   return adviceBeans;
}

会从applicationContext中获取有ControllerAdvice注解的bean

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RequestBodyAdviceResponseBodyAdvice是用于对请求和响应的消息进行处理的接口。它们可以在HttpMessageConverter转换消息之前和之后对消息进行定制化操作。 HttpMessageConverter是用于将请求和响应的消息与Java对象进行转换的组件。它负责将请求的消息转换为方法参数的对象,并将方法的返回值转换为响应的消息。 具体来说,在请求的处理过程中,HttpMessageConverter首先会将请求的消息转换为Java对象。在这个过程中,可以使用RequestBodyAdvice接口的beforeBodyRead方法在消息转换之前对请求的消息进行处理。然后,HttpMessageConverter会将转换后的Java对象作为参数传递给业务方法进行处理。在业务方法处理完毕后,HttpMessageConverter会将方法的返回值再次转换为响应的消息。在这个过程中,可以使用ResponseBodyAdvice接口的beforeBodyWrite方法在消息转换之后对响应的消息进行处理。 因此,RequestBodyAdviceResponseBodyAdvice可以在HttpMessageConverter转换消息的前后对消息进行修改、记录日志或添加额外的信息等操作。它们提供了更灵活的方式来对请求和响应的消息进行定制化处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spring解密之RequestBodyAdviceResponseBodyAdvice、HttpMessageConverter](https://blog.csdn.net/Sophisticated_/article/details/102614321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [ResponseBodyAdvice和HttpMessageConverter应用浅析](https://blog.csdn.net/qq_26950567/article/details/115263381)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊森的代码园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值