引入
Socket与SeverSocket
- Socket
Socket是网络连接的一个端点。套接字使得一个应用可以从网络中读取和写入数据。放在两 个不同计算机上的两个应用可以通过连接发送和接受字节流。
在 Java 里边,套接字指的是java.net.Socket类。
public Socket (java.lang.String host, int port)
- ServerSocket
ServerSocket 和 Socket 不同,服务器套接字的角色是等待来自客户端的连接请求。一旦服务器套接字获得一个连接请求,它创建一个 Socket 实例来与客户端进行通信。
其中一个 ServerSocket 类的构造方法如下所示:
public ServerSocket(int port, int backLog, InetAddress bindingAddress);
服务器套接字的另一个重要的属性是 backlog,这是服务器套接字开始拒绝传入的请求之前,传入的连接请求的最大队列长度。
一个简单Web容器设计与实现
根据上述的基础,我们可以看到,我们只需要提供三个最基本的类,分别是:
- Request - 表示请求,这里表示浏览器发起的HTTP请求
- HttpServer - 表示处理请求的服务器,同时这里使用我们上面铺垫的ServerSocket
- Reponse - 表示处理请求后的响应, 这里表示服务器对HTTP请求的响应结果
更复杂的实现,如果我们需要对于一个请求,有对应的Servlet来做处理,我们可以将组件设计成为这样:
理解Tomcat架构设计
什么是Servlet
一个Servlet主要做下面三件事情:
- 创建并填充Request对象,包括:URI、参数、method、请求头信息、请求体信息等
- 创建Response对象
- 执行业务逻辑,将结果通过Response的输出流输出到客户端
Servlet没有main方法,所以,如果要执行,则需要在一个容器里面才能执行,这个容器就是为了支持Servlet的功能而存在,Tomcat其实就是一个Servlet容器的实现。
Tomcat——Servlet容器
- Server: 表示服务器,它提供了一种优雅的方式来启动和停止整个系统,不必单独启停连接器和容器;它是Tomcat构成的顶级构成元素,所有一切均包含在Server中;
- Service: 表示服务,Server可以运行多个服务。比如一个Tomcat里面可运行订单服务、支付服务、用户服务等等;Server的实现类StandardServer可以包含一个到多个Services, Service的实现类为StandardService调用了容器(Container)接口,其实是调用了Servlet Engine(引擎),而且StandardService类中也指明了该Service归属的Server;
- Container: 表示容器,可以看做Servlet容器;引擎(Engine)、主机(Host)、上下文(Context)和Wraper均继承自Container接口,所以它们都是容器。
- Connector: 表示连接器, 它将Service和Container连接起来,首先它需要注册到一个Service,它的作用就是把来自客户端的请求转发到Container(容器),这就是它为什么称作连接器。它支持的协议有AJP协议、Http协议、Https协议。
所以,假设来自客户的请求为:http://localhost:8080/test/index.jsp 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector,它被处理的过程是这样的:
- Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应
- Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host
- 对应的Host获得请求,匹配它所拥有的所有Context
- path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet
- Context 匹配到URL PATTERN为.jsp的servlet* ,对应于JspServlet类,构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
- 层层返回:Context把执行完了之后的HttpServletResponse对象返回给Host,Host把HttpServletResponse对象返回给Engine,Engine把HttpServletResponse对象返回给Connector,Connector把HttpServletResponse对象返回给客户browser
小知识:
Container容器按照责任链的设计模式,使用管道Pipeline和Value的方式来传递请求。
- 当一个request过来的时候,需要对这个request做一系列的加工,使用责任链模式可以使每个加工组件化,减少耦合。也可以使用在当一个request过来的时候,需要找到合适的加工方式。当一个加工方式不适合这个request的时候,传递到下一个加工方法,该加工方式再尝试对request加工。
- 这很好记的解释了Java架构直通车——过滤器和拦截器使用一文中,过滤器的位置和运作方式。