无图言屌:
以前我们用servlet进行编程:
所有的配置都会在配置在web.xml里面,其实类似于现在的任务编排
我们会把我们的Filter和Servlet还有Listener,初始化的一些参数都写到web.xml中,
然后相信大家也都看到了上面的这张图,里面有两个Context,这两个都是servletcontext,对应的是两个web应用,一个servletcontext对应的是一个web应用,里面会存放这个应用中所有的servlet会共同用到的信息,以及web.xml里面的信息都会在里面存储。servletContext加载的顺序是,Listener->Filter->Servlet
- 相信大家也都知道了,当我们发送一个请求的时候,和我们自己的web应用相关的,tomcat会先加载我们web.xml.其实在tomcat的配置目录下面也有一个默认的web.xml,也会被tomcat读取并加载。我们的程序可以自定义的三个环节,就是Listener, Filter和Servlet。
- Servlet先加载Listener,ServletContextListener接口能够监听ServletContext对象的生命周期,因为每个web应用仅有一个ServletContext对象,故实际上该接口监听的是整个web应用。
- 然后会先经过我们的Filter过滤器链,当然我们也可以实现或者继承Fillter相关的接口或雷,编写我们自己的Filter,然后配置在我们的Web.xml里面,容器就会在读取web.xml时候,加载我们的配置信息进ServletContext(Context是上下文不是容器)
- 然后才会根据请求的uri找到我们对应的Servlet处理我们的request请求,最后返回我们的response请求。
后来我们使用了SpringMVC进行编程:
但是我们仍然是基于Tomcat提供的容器的,所以我们的大致流程还是需要在web.xml进行注册,但是我们的程序怎么从Servlet进入到Spring的MVC的写Controller用@Controller和@RequestMapping时代的呢?
其实Spring算是一个独立的世界,Servlet是另外一个世界,从一个世界到另外一个世界就需要一个桥,代理,分发器叫什么都好?无所谓。
SpringMVC有自己的Filter规则,所以有了在web.xml中加入了如下配置:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-application.xml</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
从上面的流程我们可以知道,在这里我们配置了一个ContextLoaderListener,org.springframework.web.context.ContextLoaderListener类实现了javax.servlet.ServletContextListener接口。ServletContextListener接口能够监听ServletContext对象的生命周期,因为每个web应用仅有一个ServletContext对象,故实际上该接口监听的是整个web应用。
- 根据执行顺序,Tomcat容器先加载web.xml生成ServletContext,
- 然后加载ContextLoaderListener,这个listener是Spring的,他的首要任务就是实例化一个WebApplicationContext,在ServletContext里面注册为key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=“WebApplicationContext.ROOT”, value为实例化出来的WebApplicationContext,对象将无论是注解形式的还是基于xml配置的bean加载到WebApplicationContext中。供后面使用。
- DelegatingFilterProxy就是从源生的Filter到Spring内部所需要的Filter的桥,比如SpringSecurity里面涉及到的Filter,至于怎么实现的,肯定是通过webApplicationContext加载的啦,
- 从Servlet到SpringMVC的Controller 这个桥是DispatcherServlet,之前我们的Servlet是一个Servlet对应一个uri,但是我们的Controller中是一个Method对应一个uri,但是不用担心因为spring有对应的HandlerAdapter:RequestMappingHandlerAdapter这个HandlerAdapter他有个protected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception 方法负责解决这个。
大家记住Spring的东西是通过Spring中的ApplicationContext获取的,这也是为什么Spring的两个特性IOC控制反转 DI依赖注入的牛逼的地方,
总结一下:
- ServletContext是对应于整个应用的所有的Servlet的公共资源,对应的是web.xml,
- ApplicationContext对应的是Spring的整个公共资源,对应的文件时ApplicationContext.
- WebApplicationContext其实是SpringMVC的,也是ApplicationContext的一种,是对应的web的而已。一般web项目中会形成两个Context,一个是ServletContext这个是容器的上下文,一个是WebApplicationContext是Spring环境中的上下文,而且两者彼此可以相互get到对方,你中有我我中有你,如servletContext.get("WebApplicationContext.ROOT")获得WebApplicationContext实例, WebApplicationContext.getServletContext()获得ServletContext对象
以上我们还写Web.xml,可是后来逐渐地不知道什么时候我们开始不去写web.xml了,逐渐的我们的封装程度越来越高,导致我们距离基础越来越远了,用起来糊里糊涂的.但是无论我们还写不写web.xml,web应用的整个启动流程是这样的保持不变,这些环节和顺序是这样的, 关于web.xml为什么消失了,大家可以参考下面链接:Spring 揭秘 -- 寻找遗失的 web.xml - 徐靖峰|个人博客
参考:
https://wiki.jikexueyuan.com/project/spring-security/filter.html