正所谓前人栽树,后人乘凉。
感谢Huxpro提供的博客模板
1、问题来源
使用SpringBoot 搭建api项目时,需要对api接口进行统一的解密和加密。
加密解密时机:1、SpringMVC 套餐 @ControllerAdvice 、 HttpInputMessage、RequestBodyAdvice
2、使用HttpMessageConverter
3、Servlet Api 过滤器 Filter
经过测试发现:[email protected],并且对请求Content-Type 进行一些配置,可以实现但是并不友好;
[email protected],Content-Type则在转换器中支持所有类型即可;另外从下面的转换方法的方法签名可以看出,需要返回具体的对象,若controller中入参的对象结构比较复杂,返回这个对象会有一定的成本。本着开发时能交给框架就交给框架的懒人原则 :) protected Object readInternal(Class> clazz, HttpInputMessage inputMessage)
方案3 众所周知是一定可以实现的,并且对请求的后续mvc的处理流程完全透明,是比较理想的方案。
最后选择方案3
好了,已经偏题了
项目中同时也是使用了Filter做请求log,于是出现了LogFilter中log不到请求参数的问题,理想状态是解密的Filter第一个被执行,后续再执行其他的Filter。
2、面向Google编程
google到排序的方法:1、根据filter名自然排序的顺序执行(测试不行)
2、xml配置文件中配置filter的先后顺序(springboot还写xml?)
3、使用FilterRegistrationBean向Spring容器注册bean,同时指定FilterRegistrationBean的order值(亲测可行,但每个filter都需要写一个FilterRegistrationBean,不优雅,嫌弃)
4、使用注解@ServletComponentScan(亲测不行,原因后续会提到)
google没找到满意的解决方法,还是自己看下为什么不能排序吧。
3、解决方法
这里写下处理方法:
添加@Order、@Component即可,其他不需要处理。并且不能使用@ServletComponentScan,或者@ServletComponentScan的扫描范围不能包括想要排序的Filter
4、排序分析
1、filter执行链执行方式
a. 通过断点进去filterChain#doFilter方法
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if( Globals.IS_SECURITY_ENABLED ) {
// ...
internalDoFilter(req,res);
// ...
} else {
internalDoFilter(request,response);
}
}
b. 跟踪进入 internalDoFilter 可以看到如下关键代码
private void internalDoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
// 获取并偏移下标
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
// ...
// 执行过滤器逻辑(递归)
filter.doFilter(request, response, this);
}
// ...
// 所有过滤器前置执行结束,执行servlet
servlet.service(request, response);
// 执行servlet执行结束,递归出口
// ...
这里看到filters[pos++],这是Filter责任链模式实现的核心,从filterChain内维护的filter列表依次获取并执行。Servlet的Filter责任链模式是通过filter列表和递归调用实现的。
于是我们得到一个结论:filter的执行顺序取决与filter在filterChain的Filters列表的顺序,继续跟进Filters列表创建
2、Filters列表的创建
找到ApplicationFilterChain#addFilter方法,filters由外部添加,断点继续往找;
找到ApplicationFilterFactory#createFilterChain方法,在这里创建处理链,如下:
public static ApplicationFilterChain createFilterChain(ServletRequest request,
Wrapper wrapper, Servlet servlet) {
// ...
// 创建处理链
filterChain = new ApplicationFilterChain();