【记录版】重新认识Springboot内嵌servlet容器后的Filter

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, 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,即最后,那就看扫描顺序了。

你可能感兴趣的:(Filter,spring,boot,Filter)