目录
回到顶部
开心一刻
过年女婿来岳父家走亲戚,当时小舅子主就问:姐夫,你什么时候能给我姐幸福,让我姐好好享受生活的美好。你们这辈子不准备买一套大点的房子吗?姐夫说:现在没钱啊!不过我有一个美丽可爱的女儿,等长大后找个有钱的老公嫁了,那时我就能和你姐一起住大房子了。岳父不乐意的说了一句:当初我也是这么认为的,可惜未能如愿。
路漫漫其修远兮,吾将上下而求索!
github:https://github.com/youzhibing
码云(gitee):https://gitee.com/youzhibing
回到顶部
定义了servlet与其servlet容器通信的一些列方法,例如,获取文件的MIME类型,分派请求或写入日志文件。
Servlet的运行模式是一个典型的“握手型的交互式”运行模式。所谓“握手型的交互式”就是两个模块为了交换数据通常都会准备一个交易场景,这个场景一直跟随这个交易过程直到这个交易完成为止。这个交易场景的初始化是根据这次交易对象指定的参数来定制的,这些制定参数通常就是一个配置类。所以对号入座,交易场景由ServletContext来描述,而定制的参数集合由ServletConfig来描述。而ServletRequest和ServletResponse就是要交互的具体对象,它们通常都作为运输工具来传递交互结果。ServletContext,即servlet上下文,用于存放web应用信息;每个Java虚拟机每个Web项目只有一个ServletContext,它是由Web服务器创建,代表当前web应用。
我们采用2.5来看下源码
maven依赖
View Code
源码
View Code
定义了 一些列的方法,具体就不看了,有兴趣的可以详细看下
我们采用4.0.1来看下源码
maven依赖
View Code
源码
View Code
从3.0新增的方法,方法描述上都有标明@since Servlet 3.0,大家可以去细看下3.0具体新增了哪些方法。新增的add系列方法如下
也就是说可以通过ServletContext向servlet容器添加Filter、Listener和Servlet了。
3.0之前和3.0之后,maven依赖的artifactId是不同的,大家需要注意一下;
servlet 3.0是一个大的版本变动,相比之前增加了比较多的特性,本文就涉及到其中一个特性:支持无web.xml配置(新的注解支持)
servlet 3.0及之后,Filter、Servlet和Listener支持注解配置(3.0之前都是配置在web.xml中)
回到顶部
实现Filter接口实现我们自己的Filter,这个与web.xml时期一样
View Code
利用FilterRegistrationBean将我们自定义的Filter注册到容器
View Code
工程详情请点:spring-boot-filter;FilterRegistrationBean的作用与在web.xml中配置Filter类似,只是底层用了servlet3.0的新特性
我们知道servlet3.0+,可以通过ServeltContext来注册Filter(当然还包括Servlet、Listener)到Servlet容器;至于注册到Servlet容器后,容器容器如何处理Filter就不是本文的范畴了。我们姑且这样认为:通过ServletContext注册Filter到容器,那么Filter就能起到过滤作用了。那么问题来了,springboot是如何将Filter注册到容器的?
FilterRegistrationBean的源码
View Code
FilterRegistrationBean的类描述:一个用于向Servlet 3.0+容器注册Filter的ServletContextInitializer,类似于ServletContext提供的ServletContext#addFilter(String,Filter)注册功能,但具有Spring Bean特性的友好设计。相当于对ServletContext#addFilter进行了spring bean的友好性适配,本质还是ServletContext#addFilter。
我们来看看ServletContextInitializer,感觉和ServeltContext有很大的关系,源码如下
View Code
ServletContextInitializer允许我们以编程方式配置Servlet 3.0+ ServletContext上下文,并且SpringServletContainerInitializer不会检测到实现此接口的类(类没有实现WebApplicationInitializer),因此不会被Servlet容器自动引导;ServletContextInitializer的设计目的是由spring管理,而不是Servlet容器。ServletContextInitializer就一个方法:onStartup,我们顺着FilterRegistrationBean的类图来看看onStartup的实现
我们发现,最终还是调用ServletContext的addFilter方法将Filter注册到Servlet容器。问题又来了,ServletContextInitializer的onStartup又是在哪里被调用的呢?
springboot的启动过程中肯定在哪个地方对ServletContextInitializer的onStartup进行了调用,我们接着往下看,我们从ServletWebServerApplicationContext.java的createWebServer方法开始(Springboot启动开始到createWebServer的过程就省了)
先去spring的beanFactory中获取ServletContextInitializer的全部实例,并将其放入到ServletContextInitializerBeans的initializers中,然后遍历initializers,调用每个ServletContextInitializer的onStartup方法(有人感觉这里有点多余,其实你把initializers想成缓存就好理解了,肯定还有其他地方会用到initializers)。
至此也就通了,spring将@Bean修饰的RegistrationBean注册到beanFactory,然后从beanFactory中获取全部的ServletContextInitializer,遍历它们并调用他们的onStartup方法将RegistrationBean中的bean注册到servlet容器;但是有一点@Bean注解是如何将bean注册到beanFactory的本文没有涉及,会放到springboot启动系列篇中,敬请期待。
回到顶部
1、ServletContext是request与response交互的平台,也是我们的web应用与servlet容器沟通的桥梁;就从本文来说,Filter、Servlet、Listener的注册都是通过ServletContext来实现的
2、Servlet3.0+有很多新特性,包括Filter、Servlet、Listener的注册,不再只是通过web.xml实现了。而springboot也只是对ServletContext的add系列方法进行了拓展,使得具有spring的友好性,而FilterRegistrationBean就是具体的实现之一。
3、springboot启动过程中,调用ServletContextInitializer类型的实例的onStartup方法,完成指定bean到servlet容器的注册;指定bean就是指我们自定义的Filter、Servlet、Listener,而不是RegistrationBean类型的实例。