请求:请求行,请求头,请求体 响应:状态行,响应报文,报文主体
Cookie 本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息
Session 可以理解为服务器端开辟的存储空间,里面保存了用户的状态
当用户请求到来时,服务端可以把用户的请求和用户的 Session 对应起来。那么 Session 是怎么和请求对应起来的呢?答案是通过 Cookie,浏览器在 Cookie 中填充了一个 Session ID 之类的字段用来标识请求。
将网络上的信息实体看作是资源,可以是图片、文件、一个服务...资源用URI统一标识,URI中没有动词哦,这是因为它是资源的标识,那怎么操作这些资源呢,于是定义一些动作:GET、POST、PUT和DELETE。通过URI+动作来操作一个资源。
所谓的无状态说的是,为了完成一个操作,请求里包含了所有信息,你可以理解为服务端不需要保存请求的状态,也就是不需要保存session,没有session的好处是带来了服务端良好的可伸缩性,方便failover,请求被LB转到不同的server实例上没有差别。从这个角度看,正是有了REST架构风格的指导,才有了HTTP的无状态特性,顺便提一下,REST和HTTP1.1出自同一人之手。但是理想是丰满的,现实是骨感的,为了方便开发,大多数复杂的Web应用不得不在服务端保存Session。为了尽量减少Session带来的弊端,往往将Session集中存储到Redis上,而不是直接存储在server实例上。
在 HTTP/1.0 时期,每次 HTTP 请求都会创建一个新的 TCP 连接,请求完成后之后这个 TCP 连接就会被关闭。这种通信模式的效率不高 HTTP/1.1 中,引入了 HTTP 长连接的概念,使用长连接的 HTTP 协议,会在响应头加入 Connection:keep-alive。这样当浏览器完成一次请求后,浏览器和服务器之间的 TCP 连接不会关闭,再次访问这个服务器上的网页时,浏览器会继续使用这一条已经建立的连接,也就是说两个请求可能共用一个 TCP 连接。 HTTP/1.1中的长连接依然没有解决 head of line blocking 的问题,后面的连接必须等待前面的返回了才能够发送,这个问题直到HTTP/2.0采取二进制分帧编码方式才彻底解决。
Servlet 本质上是一个接口,实现了 Servlet 接口的业务类也叫 Servlet。Servlet 接口其实是 Servlet 容器跟具体 Servlet 业务类之间的接口。Servlet 接口跟 Servlet 容器这一整套规范叫作 Servlet 规范,而 Servlet 规范使得程序员可以专注业务逻辑的开发,同时 Servlet 规范也给开发者提供了扩展的机制 Filter 和 Listener。
public interface Servlet { void init(ServletConfig config) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest req, ServletResponse res)throws ServletException, IOException; String getServletInfo(); void destroy(); } 复制代码
Servlet 规范里定义了 ServletContext 这个接口来对应一个 Web 应用。Web 应用部署好后,Servlet 容器在启动时会加载 Web 应用,并为每个 Web 应用创建唯一的 ServletContext 对象。你可以把 ServletContext 看成是一个全局对象,一个 Web 应用可能有多个 Servlet,这些 Servlet 可以通过全局的 ServletContext 来共享数据,这些数据包括 Web 应用的初始化参数、Web 应用目录下的文件资源等。由于 ServletContext 持有所有 Servlet 实例,你还可以通过它来实现 Servlet 请求的转发。
Filter 是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理,比如你可以根据请求的频率来限制访问,或者根据国家地区的不同来修改响应内容。过滤器的工作原理是这样的:Web 应用部署完成后,Servlet 容器需要实例化 Filter 并把 Filter 链接成一个 FilterChain。当请求进来时,获取第一个 Filter 并调用 doFilter 方法,doFilter 方法负责调用这个 FilterChain 中的下一个 Filter。
Listener 是监听器,这是另一种扩展机制。当 Web 应用在 Servlet 容器中运行时,Servlet 容器内部会不断的发生各种事件,如 Web 应用的启动和停止、用户请求到达等。 Servlet 容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet 容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。比如 Spring 就实现了自己的监听器,来监听 ServletContext 的启动事件,目的是当 Servlet 容器启动时,创建并初始化全局的 Spring 容器。
1.Filter是Servlet规范的一部分,是Servlet容器Tomcat实现的。 2.Intercepter是Spring发明的。 3.它们的执行顺序是: Filter.doFilter(); HandlerInterceptor.preHandle(); Controller; HandlerInterceptor.postHandle(); DispatcherServlet 渲染视图 HandlerInterceptor.afterCompletion(); Filter.doFilter(); Servlet方法返回;
Filter 是干预过程的,它是过程的一部分,是基于过程行为的。 Listener 是基于状态的,任何行为改变同一个状态,触发的事件是一致的。
Servlet容器,是用于管理Servlet生命周期的。 Spring容器,是用于管理Spring Bean生命周期的,如service,dao等。 SpringMVC容器,适用于管理SpringMVC Bean生命周期的,如Controller,ViewResovler等。
Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:
对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext
ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置
如果Listener中配有spring的ContextLoaderListener
如果Servlet中配有SpringMVC的DispatcherServlet
附一个描述关系的图 blog.csdn.net/zhanglf02/a…
这里简要介绍各个文件的含义。
以下两种配置都可以将servlet注给servlet容器
<servlet> <servlet-name>myServlet</servlet-name> <servlet-class>MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>myServlet</servlet-name> <url-pattern>/myservlet</url-pattern> </servlet-mapping> 复制代码
@WebServlet("/myAnnotationServlet") public class AnnotationServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //TODO } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //TODO } 复制代码
Servlet接口中定义了service方法,没有doGet/doPost。HttpServlet是一个实现类,实现了service方法,同时留出了doGet/doPost方法让程序员来实现。