RequestBodyAdvice和ResponseBodyAdvice
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相关推荐
- 在spring中使用RequestBodyAdvice 和 ResponseBodyAdvice增强器
前言 Advice 直译为通知,也有人翻译为 "增强处理",不过一般的增强器是带有Advisor的类. 前言: 日常开发中,我们常常需要对@RequestBody的参数进行各种 ...
- RequestBodyAdvice 和 ResponseBodyAdvice增强器使用
前言: 日常开发中,我们常常需要对@RequestBody的参数进行各种处理,例如加解密.打印日志,这些东西我们可以用到RequestBodyAdvice 和 ResponseBodyAdvice ...
- SpringBoot 基于RequestBodyAdvice 和 ResponseBodyAdvice 实现数据的加/解密(采用 RSA 算法 ),“船新版本”!
一.前言: 数据是企业的第四张名片,企业级开发中少不了数据的加密传输.为了预防请求数据被劫持篡改,一般都会对传输的数据进行加密操作,如果每个接口都由我们自己去手动加密和解密,那么工作量太大而且代码冗余 ...
- 面试官:Java中 serialVersionUID 的作用是什么?举个例子说明
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料!来源:blog.csdn.net/andy_zhang200 ...
- SpringMVC:注解@ControllerAdvice的工作原理
点击上方蓝色"方志朋",选择"设为星标"回复"666"获取独家整理的学习资料! 来源:blog.csdn.net/andy_zhang200 ...
- api怎么写_API数据加密框架monkeyapiencrypt
之前有写过一篇加密的文章<前后端API交互如何保证数据安全性>. 主要是在Spring Boot中如何对接口的数据进行自动加解密操作,通过注解的方式来指定是否需要加解密. 原理也很简单,通 ...
- 前后端API交互如何保证数据安全性?
本文转载自公众号: 猿天地 1.前言 前后端分离的开发方式,我们以接口为标准来进行推动,定义好接口,各自开发自己的功能,最后进行联调整合.无论是开发原生的APP还是webapp还是PC端的软件,只要是 ...
- spring mvc框架设计与实现
spring mvc框架通过DispatcherServlet来作请求分发,主要由HandlerMapping,HandlerAdapter,HandlerInterceptor三个抽象来完成.通过H ...
- Spring4+SpringMVC+MyBatis整合思路
本文主要简单讲解框架整合的思路. 1.Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListene ...
最新文章
- nyoj 234 吃土豆
- c++内存管理的一些资料
- 根据 xsd 生成 jaxb java 类
- Kubernetes应用部署模型解析(原理篇)
- 服务器用户配置文件在哪里找,管理远程桌面服务的用户配置文件
- js中select下拉框重置_如何利用CSS3制作炫酷的下拉框
- dubbo-go 中如何实现路由策略功能
- MFC修改窗口无标题和标题信息,修改执执行文件图标
- 服务器关机显示正在停止服务,云服务器一直停止中
- 物联网时代的技术迷雾
- 小白白红队初成长(5)win权限维持
- 黑马JAVA P165 代码与文件编码不一致读取乱码的问题、转换流来解决
- HttpWatch使用教程
- filters过滤器的简单使用
- 拉普拉斯矩阵 拉普拉斯算子 图论
- 12.5米分辨率DEM
- leetcode_263:丑数(丑数II)
- js代码中用单个字母命名
- Top 和 LIMIT
- jQuery 获取复选框选中状态
热门文章
- 2016.5.57—— Remove Duplicates from Sorted List
- 基础中的基础。CANVAS step01
- python代码没有错误却无法运行的原因-Python shell没有显示错误,但程序没有运行...
- python新手代码-Python的初学者你现在可以自己“看”到代码的运行了!
- python做些什么-学会Python后都能做什么?网友们的回答简直不要太厉害
- 用requests获取网页源代码 python-手把手教你利用爬虫爬网页(Python代码)
- python画五角星-Python第八课 绘制五角星1.0
- 不想学python-为什么自学python总是坚持不下去,这篇文章给你解答!
- python能做软件吗-python能够做软件的自动化测试吗?
- 软件测试用python一般用来做什么-如何将Python应用到实际测试工作中?