1、类层次结构

1.1 RequestBodyAdviceAdapter

实现了beforeBodyRead,afterBodyRead,handleEmptyBody,只是简单实现,不作任何处理,直接返回

public abstract class RequestBodyAdviceAdapter implements RequestBodyAdvice {/*** The default implementation returns the InputMessage that was passed in.*/@Overridepublic HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType)throws IOException {return inputMessage;}/*** The default implementation returns the body that was passed in.*/@Overridepublic Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return body;}/*** The default implementation returns the body that was passed in.*/@Override@Nullablepublic Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage,MethodParameter parameter, Type targetType,Class<? extends HttpMessageConverter<?>> converterType) {return body;}}

1.2 JsonViewRequestBodyAdvice

继承RequestBodyAdviceAdapter。处理JsonView注解。

support方法判断converterType是不是AbstractJackson2HttpMessageConverter子类以及方法参数是否有参数注解@JsonView

public boolean supports(MethodParameter methodParameter, Type targetType,Class<? extends HttpMessageConverter<?>> converterType) {return (AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType) &&methodParameter.getParameterAnnotation(JsonView.class) != null);}

beforeBodyRead方法获取@JsonView注解的值,并且设置的值的长度必须为1,基于配置的类信息创建MappingJacksonInputMessage

public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter,Type targetType, Class<? extends HttpMessageConverter<?>> selectedConverterType) throws IOException {JsonView ann = methodParameter.getParameterAnnotation(JsonView.class);Assert.state(ann != null, "No JsonView annotation");Class<?>[] classes = ann.value();if (classes.length != 1) {throw new IllegalArgumentException("@JsonView only supported for request body advice with exactly 1 class argument: " + methodParameter);}return new MappingJacksonInputMessage(inputMessage.getBody(), inputMessage.getHeaders(), classes[0]);}

1.3 RequestResponseBodyAdviceChain

实现了RequestBodyAdvice,ResponseBodyAdvice,RequestBodyAdvice和ResponseBodyAdvice的链式处理。在初始化时,会将advice分成两组RequestBodyAdvcie组和ResponseBodyAdvice组。

public RequestResponseBodyAdviceChain(@Nullable List<Object> requestResponseBodyAdvice) {this.requestBodyAdvice.addAll(getAdviceByType(requestResponseBodyAdvice, RequestBodyAdvice.class));this.responseBodyAdvice.addAll(getAdviceByType(requestResponseBodyAdvice, ResponseBodyAdvice.class));}@SuppressWarnings("unchecked")static <T> List<T> getAdviceByType(@Nullable List<Object> requestResponseBodyAdvice, Class<T> adviceType) {if (requestResponseBodyAdvice != null) {List<T> result = new ArrayList<>();for (Object advice : requestResponseBodyAdvice) {Class<?> beanType = (advice instanceof ControllerAdviceBean ?((ControllerAdviceBean) advice).getBeanType() : advice.getClass());if (beanType != null && adviceType.isAssignableFrom(beanType)) {result.add((T) advice);}}return result;}return Collections.emptyList();}

beforeBodyAdvice方法查的与当前MethodParameter及adviceType匹配的Advice列表,遍历当前Advice是否支持,如果支持,则执行beforeBodyRead

public HttpInputMessage beforeBodyRead(HttpInputMessage request, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {if (advice.supports(parameter, targetType, converterType)) {request = advice.beforeBodyRead(request, parameter, targetType, converterType);}}return request;}private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) {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 = adviceBean.resolveBean();}if (adviceType.isAssignableFrom(advice.getClass())) {result.add((A) advice);}}return result;}

afterBodyRead与beforeBodyRead类似

public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {if (advice.supports(parameter, targetType, converterType)) {body = advice.afterBodyRead(body, inputMessage, parameter, targetType, converterType);}}return body;}

beforeBodyWrite也与读类似

public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType contentType,Class<? extends HttpMessageConverter<?>> converterType,ServerHttpRequest request, ServerHttpResponse response) {return processBody(body, returnType, contentType, converterType, request, response);}private <T> Object processBody(@Nullable Object body, MethodParameter returnType, MediaType contentType,Class<? extends HttpMessageConverter<?>> converterType,ServerHttpRequest request, ServerHttpResponse response) {for (ResponseBodyAdvice<?> advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) {if (advice.supports(returnType, converterType)) {body = ((ResponseBodyAdvice<T>) advice).beforeBodyWrite((T) body, returnType,contentType, converterType, request, response);}}return body;}

handleEmptyBody类似

public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {if (advice.supports(parameter, targetType, converterType)) {body = advice.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);}}return body;}

1.4 AbstractMappingJacksonResponseBodyAdvice

support方法判断converterType是否是AbstractJackson2HttpMessageConverter子类。

public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return AbstractJackson2HttpMessageConverter.class.isAssignableFrom(converterType);}

beforeBodyWrite方法会根据body创建MappingJacksonValue,然后调用抽象方法beforeBodyWriteInternal。

public final Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType,MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType,ServerHttpRequest request, ServerHttpResponse response) {if (body == null) {return null;}MappingJacksonValue container = getOrCreateContainer(body);beforeBodyWriteInternal(container, contentType, returnType, request, response);return container;}protected MappingJacksonValue getOrCreateContainer(Object body) {return (body instanceof MappingJacksonValue ? (MappingJacksonValue) body : new MappingJacksonValue(body));}protected abstract void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response);

1.6 JsonViewResponseBodyAdvice

继承AbstractMappingJacksonResponseBodyAdvice。

supports方法除了需要满足父类的supports方法,还需要判断returnType有方法注解@JsonView

public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return super.supports(returnType, converterType) && returnType.hasMethodAnnotation(JsonView.class);}

beforeWriteBodyInternal方法获取方法注解@JsonView的值(配置的class长度为1),然后调用MappingJacksonValue.setSerializationView

protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {JsonView ann = returnType.getMethodAnnotation(JsonView.class);Assert.state(ann != null, "No JsonView annotation");Class<?>[] classes = ann.value();if (classes.length != 1) {throw new IllegalArgumentException("@JsonView only supported for response body advice with exactly 1 class argument: " + returnType);}bodyContainer.setSerializationView(classes[0]);}

2、ControllerAdvice、RestControllerAdvice注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {@AliasFor("basePackages")String[] value() default {};@AliasFor("value")String[] basePackages() default {};Class<?>[] basePackageClasses() default {};Class<?>[] assignableTypes() default {};Class<? extends Annotation>[] annotations() default {};
}@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {@AliasFor(annotation = ControllerAdvice.class)String[] value() default {};@AliasFor(annotation = ControllerAdvice.class)String[] basePackages() default {};@AliasFor(annotation = ControllerAdvice.class)Class<?>[] basePackageClasses() default {};@AliasFor(annotation = ControllerAdvice.class)Class<?>[] assignableTypes() default {};@AliasFor(annotation = ControllerAdvice.class)Class<? extends Annotation>[] annotations() default {};
}

3、Advice的初始化

是通过ControllerAdviceBean来查找所有的RequestBodyAdvcie,ResponseBodyAdvice的

findAnnotatedBeans找到所有的Advice

public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {ListableBeanFactory beanFactory = context;if (context instanceof ConfigurableApplicationContext) {// Use internal BeanFactory for potential downcast to ConfigurableBeanFactory abovebeanFactory = ((ConfigurableApplicationContext) context).getBeanFactory();}List<ControllerAdviceBean> adviceBeans = new ArrayList<>();for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Object.class)) {if (!ScopedProxyUtils.isScopedTarget(name)) {ControllerAdvice controllerAdvice = beanFactory.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, beanFactory, controllerAdvice));}}}OrderComparator.sort(adviceBeans);return adviceBeans;

RequestBodyAdvice和ResponseBodyAdvice相关推荐

  1. 在spring中使用RequestBodyAdvice 和 ResponseBodyAdvice增强器

    前言 Advice 直译为通知,也有人翻译为 "增强处理",不过一般的增强器是带有Advisor的类. 前言:   日常开发中,我们常常需要对@RequestBody的参数进行各种 ...

  2. RequestBodyAdvice 和 ResponseBodyAdvice增强器使用

    前言:   日常开发中,我们常常需要对@RequestBody的参数进行各种处理,例如加解密.打印日志,这些东西我们可以用到RequestBodyAdvice 和 ResponseBodyAdvice ...

  3. SpringBoot 基于RequestBodyAdvice 和 ResponseBodyAdvice 实现数据的加/解密(采用 RSA 算法 ),“船新版本”!

    一.前言: 数据是企业的第四张名片,企业级开发中少不了数据的加密传输.为了预防请求数据被劫持篡改,一般都会对传输的数据进行加密操作,如果每个接口都由我们自己去手动加密和解密,那么工作量太大而且代码冗余 ...

  4. 面试官:Java中 serialVersionUID 的作用是什么?举个例子说明

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料!来源:blog.csdn.net/andy_zhang200 ...

  5. SpringMVC:注解@ControllerAdvice的工作原理

    点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 来源:blog.csdn.net/andy_zhang200 ...

  6. api怎么写_API数据加密框架monkeyapiencrypt

    之前有写过一篇加密的文章<前后端API交互如何保证数据安全性>. 主要是在Spring Boot中如何对接口的数据进行自动加解密操作,通过注解的方式来指定是否需要加解密. 原理也很简单,通 ...

  7. 前后端API交互如何保证数据安全性?

    本文转载自公众号: 猿天地 1.前言 前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合.无论是开发原生的APP还是webapp还是PC端的软件,只要是 ...

  8. spring mvc框架设计与实现

    spring mvc框架通过DispatcherServlet来作请求分发,主要由HandlerMapping,HandlerAdapter,HandlerInterceptor三个抽象来完成.通过H ...

  9. Spring4+SpringMVC+MyBatis整合思路

    本文主要简单讲解框架整合的思路. 1.Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListene ...

最新文章

  1. nyoj 234 吃土豆
  2. c++内存管理的一些资料
  3. 根据 xsd 生成 jaxb java 类
  4. Kubernetes应用部署模型解析(原理篇)
  5. 服务器用户配置文件在哪里找,管理远程桌面服务的用户配置文件
  6. js中select下拉框重置_如何利用CSS3制作炫酷的下拉框
  7. dubbo-go 中如何实现路由策略功能
  8. MFC修改窗口无标题和标题信息,修改执执行文件图标
  9. 服务器关机显示正在停止服务,云服务器一直停止中
  10. 物联网时代的技术迷雾
  11. 小白白红队初成长(5)win权限维持
  12. 黑马JAVA P165 代码与文件编码不一致读取乱码的问题、转换流来解决
  13. HttpWatch使用教程
  14. filters过滤器的简单使用
  15. 拉普拉斯矩阵 拉普拉斯算子 图论
  16. 12.5米分辨率DEM
  17. leetcode_263:丑数(丑数II)
  18. js代码中用单个字母命名
  19. Top 和 LIMIT
  20. jQuery 获取复选框选中状态

热门文章

  1. 2016.5.57—— Remove Duplicates from Sorted List
  2. 基础中的基础。CANVAS step01
  3. python代码没有错误却无法运行的原因-Python shell没有显示错误,但程序没有运行...
  4. python新手代码-Python的初学者你现在可以自己“看”到代码的运行了!
  5. python做些什么-学会Python后都能做什么?网友们的回答简直不要太厉害
  6. 用requests获取网页源代码 python-手把手教你利用爬虫爬网页(Python代码)
  7. python画五角星-Python第八课 绘制五角星1.0
  8. 不想学python-为什么自学python总是坚持不下去,这篇文章给你解答!
  9. python能做软件吗-python能够做软件的自动化测试吗?
  10. 软件测试用python一般用来做什么-如何将Python应用到实际测试工作中?