随记1)—RequestMappingHandlerAdapter对ControllerAdvice的处理
一个特殊的需求,需要对既有的全局响应做封装,该全局响应使用ControllerAdvice注解。 解决思路:开发项目自定义全局处理器,达到替换或者至少在原处理器之后调用,以便做转换处理。 SpringBoot-2.0.3.RELEASE
方案一: 替换增强 开发BeanPostProcessor,在postProcessAfterInitialization方法中,替换RequestMappingHandlerAdapter对象 → List<HandlerMethodReturnValueHandler> 集合 → RequestResponseBodyMethodProcessor 对象 → RequestResponseBodyAdviceChain 属性 → private final List<Object> responseBodyAdvice 中的增强进行处理 开发过程中发现RequestResponseBodyAdviceChain 类访问修饰符为default,无法反射取值替换,此方案失败!
方案二: 摧毁原始hanlderBean 开发BeanPostProcessor,在postProcessBeforeInitialization中对原handler进行retuan null,以此预期达到不创建此ControllerAdviceBean的目的,实测,注解扫描以及加载过程在RequestMappingHandlerAdapter的afterPropertiesSet()方法中执行(其有实现InitializingBean接口),其执行过程早于BeanPostProcessor,因为,即使后置处理器再把原全局handler对象置空,但其已创建ControllerAdviceBean并加载至内存中,此处理方案失败。
方案三: 万能的代理 预期在后置处理器中,对原全局handler对象创建cglib动态代理,后因代理对象返回值不同的客观需求,此方案失败。
方案四: 序列化前扩展 后置处理器中,扩展RequestMappingHandlerAdapter 对象中RequestResponseBodyMethodProcessor 的 handleReturnValue方法,获取 returnValue 进行类型判断以及结果封装。此序列化扩展处在ControllerAdviceBean之前处理,无论此处封装成何种对象结构,都会走到Handler中进行再包装,此方案失败。
方案五: SpringMVC拦截器 想想就迷茫,在HandlerInterceptor的afterCompletion方法中面对一个response感觉分外迷茫,不敢取值也不敢写值。
方案刘: 优先级 设置项目全局Handler的@Order(Ordered.LOWEST_PRECEDENCE),平台的handler未配置Order属性,但是默认也为最低,在AnnotationAwareOrderComparator.sort(adviceBeans);中排序,项目优先级还是高于平台的处理器,最坑的是,正常响应情况的多个Advice,会按照优先级顺序,逐个执行,也就是说,无论项目的handler做何种处理,最终都会把结果再传入到平台的Handler中做一层封装。顺便一提,关于@ExceptionHandler的处理,也是按照优先级顺序处理,只要适配到,立即处理并返回,不会全部执行。

