springMvc笔记-Filter

本文主要探讨了在SpringBoot 2.3.3版本中如何使用Filter,详细解析了Filter的加载过程,从ServletContextInitializer接口入手,分析了Filter在StandardContext初始化阶段的加载逻辑。通过代码示例和调用链,展示了Filter如何被注册到spring容器,以及在用户请求时,Filter如何参与处理流程,最终找到对应的Servlet进行服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本笔记基于springBoot 2.3.3版本

一般我们平常如果要使用Filter,会用到如下代码。

@Configuration
@ConditionalOnClass(CoreFilter.class)
public class CoreFilterAutoConfiguration {

    @Bean
    public FilterRegistrationBean coreFilterAutoConfig() {
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new CoreFilter());
        return bean;
    }
}

图中我们可以看到,在CoreFilterAutoConfiguration配置类里我们定义一个@Bean注解,将码好的CoreFilter过滤器装入FilterRegistrationBean,最后注入到spring容器中去。

源码分析:

ServletContextInitializer

这个接口是spring提供的专门给Servlet,Filter,Lister组件使用的。我们看一下其集成UML图:


图中我们可以看到,上图分别是Filter,Servlet,Listener组件的spring类UML图。我们重点看第一张Filter图。通过上文我们知道,Filter是在StandardContext初始化阶段进行加载装入的。代码如下:

for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                try {
                    1.entry.getKey().onStartup(entry.getValue(),
                            getServletContext());
                } catch (ServletException e) {
                    log.error(sm.getString("standardContext.sciFail"), e);
                    ok = false;
                    break;
                }
            }

            // Configure and call application event listeners
            if (ok) {
                2. if (!listenerStart()) {
                    log.error(sm.getString("standardContext.listenerFail"));
                    ok = false;
                }
            }

            // Check constraints for uncovered HTTP methods
            // Needs to be after SCIs and listeners as they may programmatically
            // change constraints
            if (ok) {
                checkConstraintsForUncoveredMethods(findConstraints());
            }

            try {
                // Start manager
                Manager manager = getManager();
                if (manager instanceof Lifecycle) {
                    ((Lifecycle) manager).start();
                }
            } catch(Exception e) {
                log.error(sm.getString("standardContext.managerFail"), e);
                ok = false;
            }

            // Configure and call application filters
            if (ok) {
                3. if (!filterStart()) {
                    log.error(sm.getString("standardContext.filterFail"));
                    ok = false;
                }
            }

过滤器是在1处被加载的,具体如下代码:

	private void selfInitialize(ServletContext servletContext) throws ServletException {
		prepareWebApplicationContext(servletContext);
		registerApplicationScope(servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
			beans.onStartup(servletContext);
		}
	}

selfInitialize会将从spring容器(或者叫spring应用上下文)里将ServletContextInitializer类型的Bean拿出来进行遍历执行其onStartUp方法。具体到FilterRegistrationBean方法执行顺序就是:
RegistrationBean.onStartUp ->  DynamicRegistrationBean.register -> AbstractFilterRegistrationBean.addRegistration -> ApplicationContextFacade.addFilter -> ApplicationContext.addFilter -> StandardContext.addFilterDef -> filterDefs.put

 

RegistrationBean.onStartUp -> DynamicRegistrationBean.register -> AbstractFilterRegistrationBean.configure -> ApplicationFilterRegistration.addMappingForServletNames-> StandardContext.addFilterMap-> filterMaps.add

至此过滤器就已经添加到StandardContext的filterDefs属性当中去了,并同时将fiter相关信息也添加进filterMaps里

    private Map<String, FilterDef> filterDefs = new HashMap<>();

    private final ContextFilterMaps filterMaps = new ContextFilterMaps();

1方法之后开始执行3方法filterStart,这个方法将我们刚才添加入filterDefs里的filterDef转换成ApplicationFilterConfig 并放入fiterConfigs里,代码如下:

    public boolean filterStart() {

        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Starting filters");
        }
        // Instantiate and record a FilterConfig for each defined filter
        boolean ok = true;
        synchronized (filterConfigs) {
            filterConfigs.clear();
            for (Entry<String,FilterDef> entry : filterDefs.entrySet()) {
                String name = entry.getKey();
                if (getLogger().isDebugEnabled()) {
                    getLogger().debug(" Starting filter '" + name + "'");
                }
                try {
                    ApplicationFilterConfig filterConfig =
                            new ApplicationFilterConfig(this, entry.getValue());
                    filterConfigs.put(name, filterConfig);
                } catch (Throwable t) {
                    t = ExceptionUtils.unwrapInvocationTargetException(t);
                    ExceptionUtils.handleThrowable(t);
                    getLogger().error(sm.getString(
                            "standardContext.filterStart", name), t);
                    ok = false;
                }
            }
        }

        return ok;
    }

当用户请求来时,调用链是TomcatWebServer.start -> Connector.start -> Connector.startInternal -> Http11NioProtocol.start -> NioEndpoint.start 这个方法里会创建服务器线程池,poller以及 acceptor线程。代码如下。

    @Override
    public void startInternal() throws Exception {

        if (!running) {
            running = true;
            paused = false;

            if (socketProperties.getProcessorCache() != 0) {
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
            }
            if (socketProperties.getEventCache() != 0) {
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
            }
            if (socketProperties.getBufferPool() != 0) {
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
            }

            // Create worker collection
            if (getExecutor() == null) {
                createExecutor();
            }

            initializeConnectionLatch();

            // Start poller thread
            poller = new Poller();
            Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();

            startAcceptorThread();
        }
    }

Accepter:用于接收socket连接,并将socket连接封装后,添加到Poller中去
Poller: 用于监听Socket事件,当Socket有读写事件时,将Socket封装下添加到Worker中线程任务队列中去
Worker(线程池里面的):拿到Poller传过来的socket连接后,对socket请求的预处理,包括分析报文并创建Request对象.再交给后续处理。流程图如下

 方法流程是:Acceptor run方法-> poller.run -> poller. processKey-> AbstractEndpoint.processSocket -> 请求放入到线程池 -> SocketProcessor.doRun -> AbstractProtocol.process -> AbstractProcessorLight.process -> Http11Processor.service ->

CoyoteAdapter.service -> CoyoteAdapter.postParseRequest(这个方法寻找本次请求该由那个wrapper(servlet)来处理,如下代码) -> standEngineValve.invoke -> StandardContextValve.invoke -> StandardWrapperValve.invoke -> ApplicationFilterFactory.createFilterChain(该方法会将filterMaps,filterConfigs里的所有filter取出来和servlet组成调用链) ->

ApplicationFilterChain.doFilter -> ApplicationFilterChain.internalDoFilter(先执行所有filter,然后执行servlet的service方法,即DispathServlet) -> servlet.service 方法 -> 返回用户。

** postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
    //check valves if we support async
    request.setAsyncSupported(
            connector.getService().getContainer().getPipeline().isAsyncSupported());
    // Calling the container
**    connector.getService().getContainer().getPipeline().getFirst().invoke(
            request, response);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值