SpringBoot + Filter
背景: 当前项目基本使用Springboot框架代替配置繁多的Spring框架,其中内嵌Servlet容器是其一大特征,容器内嵌后的一些核心类配置也发生了一些变化,具备了一些Spring特性,例如常见的Filter过滤器,相关配置更加简单,以下内容将以此为出发点,从相关源码阅读的基础上做个简单记录。
Servlet系列精选:
1、Servlet请求体重复读&修改新姿势
2、根据请求获取后端接口详情
3、SpringBoot下Filter注册流程
4、Filter链式执行设计解读
内嵌Servlet容器有多种,我们基本使用默认的Tomcat组件,Springboot内嵌改造后存在以下核心类:TomcatWebServer、Tomcat、TomcatStarter(implements ServletContainerInitializer)、TomcatEmbeddedContext。其中在Springboot初始化容器时,会触发TomcatEmbeddedContext的start方法,进而引起ServletWebServerApplicationContext的selfInitialize(ServletContext servletContext)的执行。
private void selfInitialize(ServletContext servletContext) throws ServletException {
this.prepareWebApplicationContext(servletContext);
this.registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
// 1、此处会处理Filter、Servlet相关实例,并将其封装成对应的注册实例
Iterator var2 = this.getServletContextInitializerBeans().iterator();
while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
// 2、此处执行从1处spring应用上下文中获取到的的过滤器注册封装Bean
beans.onStartup(servletContext);
}
}
过滤器解析的核心类为ServletContextInitializerBeans,将重点处理Spring应用上下文相关的BeanDefinition,其解析流程可参考其构造器代码:
public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) {
this.initializerTypes = initializerTypes.length != 0 ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class);
// 此处为原始逻辑,将上下文中的FilterRegistrationBean处理后放入内存
this.addServletContextInitializerBeans(beanFactory);
// 此处为springboot内嵌Servlet容器后,将Filter实现类注入容器中的适配逻辑
this.addAdaptableBeans(beanFactory);
// initializers是MultiValueMap类型,此处对value里的集合排序
// 通过适配后,SpringBoot下可将Filter自定义类通过@Component发布到容器,并可使用@Order注解实现排序
List<ServletContextInitializer> sortedInitializers = (List)this.initializers.values().stream().flatMap((value) -> {
return value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE);
}).collect(Collectors.toList());
this.sortedList = Collections.unmodifiableList(sortedInitializers);
}
注:
1、initializers值为MultiValueMap<Class<?>, ServletContextInitializer>类型,值可以是实例集合。
2、解析后的Filter类型的ServletContextInitializer即可通过其onStartup方法注册到Servlet容器的上下文中
原有获取过滤器逻辑:
private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
if (initializer instanceof ServletRegistrationBean) {
Servlet source = ((ServletRegistrationBean)initializer).getServlet();
this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
} else if (initializer instanceof FilterRegistrationBean) {
// 原有逻辑需要配置成FilterRegistrationBea才能被解析,如果需要配置优先级,需要在FilterRegistrationBean对象中配置
Filter source = ((FilterRegistrationBean)initializer).getFilter();
// 此方法仅将Servlet相关核心类放入内存中,用ServletContextInitializer接口onStartup方法完成注册到Servlet上下文
this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
} else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
String source = ((DelegatingFilterProxyRegistrationBean)initializer).getTargetBeanName();
this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
} else if (initializer instanceof ServletListenerRegistrationBean) {
EventListener source = ((ServletListenerRegistrationBean)initializer).getListener();
this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
} else {
this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer);
}
}
下面将从源码角度具体分析下对Filter类的适配逻辑,源码为简略版:
// 适配逻辑入口,可以看到对Servlet和Filter做了特殊处理
protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
MultipartConfigElement multipartConfig = this.getMultipartConfig(beanFactory);
this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig));
this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter());
}
addAsRegistrationBean方法具体实现流程:
private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, ServletContextInitializerBeans.RegistrationBeanAdapter<T> adapter) {
// type即为Filter或Servlet类型,从Spring的BeanFactory容器中查找Filter或Servlet的【实例】,说明此时自定义类已经完成实例化流程
List<Entry<String, B>> entries = this.getOrderedBeansOfType(beanFactory, beanType, this.seen);
Iterator var6 = entries.iterator();
while(var6.hasNext()) {
Entry<String, B> entry = (Entry)var6.next();
String beanName = (String)entry.getKey();
B bean = entry.getValue();
if (this.seen.add(bean)) {
// RegistrationBean适配类的封装
RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
// 从bean上获取优先级值,包含@Order注解、Order实现类、@Priority注解
int order = this.getOrder(bean);
registration.setOrder(order);
this.initializers.add(type, registration);
}
}
}
适配流程的代码已经列举完成,回过头来再重新认识以下后续一个重要处理:排序!!!
(List)this.initializers.values().stream().flatMap((value) -> {
return value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE);
}).collect(Collectors.toList());
获取优先级逻辑:
// AnnotationAwareOrderComparator.class
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
return order != null ? order : this.findOrderFromAnnotation(obj);
}
@Nullable
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = obj instanceof AnnotatedElement ? (AnnotatedElement)obj : obj.getClass();
MergedAnnotations annotations = MergedAnnotations.from((AnnotatedElement)element, SearchStrategy.TYPE_HIERARCHY);
Integer order = OrderUtils.getOrderFromAnnotations((AnnotatedElement)element, annotations);
return order == null && obj instanceof DecoratingProxy ? this.findOrderFromAnnotation(((DecoratingProxy)obj).getDecoratedClass()) : order;
}
// org.springframework.core.annotation.OrderUtils.class
private static Integer findOrder(MergedAnnotations annotations) {
MergedAnnotation<Order> orderAnnotation = annotations.get(Order.class);
if (orderAnnotation.isPresent()) {
return orderAnnotation.getInt("value");
} else {
MergedAnnotation<?> priorityAnnotation = annotations.get("javax.annotation.Priority");
return priorityAnnotation.isPresent() ? priorityAnnotation.getInt("value") : null;
}
}
追加Filter注册到servlet容器上下文流程:
// AbstractFilterRegistrationBean.class
// 此处仅进行ApplicationFilterConfig封装,其它地方还有其对应的匹配元数据FilterMap注册
protected Dynamic addRegistration(String description, ServletContext servletContext) {
Filter filter = this.getFilter();
return servletContext.addFilter(this.getOrDeduceName(filter), filter);
}
结语:现在我们使用SpringBoot的Component或Order等注解直接处理Filter等实例,不再和以往纯Spring框架和Servlet容器间的那种繁复且冗余的配置,更符合我们编程的习惯,这才是我们现在遍地Springboot的原因吧。为完整理解Filter整体架构,后续将追加Filter执行过程篇。
提示:
1、如果遇到部分SDK场景考虑兼容spring框架项目,且Filter间要求严格有序(Filter可能来自不同jar依赖包或自定义类),则自己需要在FilterRegistrationBean实例中指定order值,否则提供的SDK可能存在Filter顺序加载错误导致的请求处理异常。
2、这里面其实牵扯到一个Bean顺序问题,比如调整自定义Filter在部分依赖jar的Filter或系统自置Filter之前或之后,Filter可能还没有使用Order等注解修饰的场景下的顺序问题。
3、 OrderedCharacterEncodingFilter(order:-2147483648)、OrderedFormContentFilter(order:-9900),未通过任意方式指定顺序,则默认为Integer.MAX_VALUE,即最后,那就看扫描顺序了。