回顾
之前的两篇的文章已经大概的带我们了解了tomcat的一些基本的操作,比如从零搭建我们自己的调试环境以及官方文档构建的方式,接下来的话,我将带大家来了解一下tomcat的一些基础知识,这些基础知识将以问题的方式抛出,然后引起我们自己的思考。
一、 tomcat的产生
这一部门我们从tomcat的产生来进行讨论,主要的是tomcat的构成条件。
1.1 tomcat产生的条件?
维基百科上是这么说的,Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器,按照Sun Microsystems提供的技术规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat管理和控制平台、安全局管理和Tomcat阀等。
Tomcat是由该基金会的会员和其他志愿者开发与维护的,并且是一个被置于Apache协议之下的开源软件。用户可以根据该协议免费获得其源代码及可执行文件。
简单的说就是SUN公司推出了Servlet的规范和JSP的规范,然后tomcat在这个规范上实现了自己的架构,然后基于各种设计模式和其他的依赖关系,最后在社区工作者的共同努力下构成了我们现在所看到的成品tomcat。
那么这个问题就很好回答了,如果对于我们直接的进行面向Servlet进行编程的话,毫无疑问编程的难度会增加,我们还需要从零开始实现Servlet的规范和JSP的规范,毫无疑问对于现在的我们肯定是无法忍受的。后来的tomcat也是经历了时间的检验,从推出到现在一直活跃在我们的视野,更是作为了SpringBoot的默认嵌入性服务器。(个人看来,这里有利也有弊,虽然它方便了我们的日常开发工作,但是也让我们对于这个软件的认知变得更加的模糊,只需要编辑配置文件即可,面向配置文件编程。)
1.2 tomcat vs jetty
在我们的个人认知中,可能我们现在比较常用的是tomcat,可是在之前也有一个和他性能相近的web容器,它就是Jetty。
Jetty 提供 Web 服务器和 servlet 容器,此外还提供对 HTTP/2、WebSocket、OSGi、JMX、JNDI、JAAS 和许多其他集成的支持。这些组件是开源的,可以免费用于商业用途和分发,并且还可以作为许多框架、云服务、应用程序服务器和设备的嵌入式工具。
Jetty的特性
- 可以用作 Java 应用程序服务器堆栈的一部分或完整。
- 由于其灵活性,可以作为其他框架的一部分应用。
- 支持云式操作。
- Jetty 用户友好,并且比 Tomcat 具有更好的界面。
- 与 Tomcat 相比,更适合处理并发用户。
- 该框架的概念权重较小,速度非常快,而且很薄。
- 内存小,工作速度快。
- 用户可以轻松使用它,因为所需的知识和技能很少。
tomcat的特性 - 首先tomcat在任何平台上都非常容易安装和配置。
- 尽管它提供了Web 服务器的所有功能,但其重量却非常轻。
- 有很多定制选项可以扩展其功能。
- 非常稳定的产品,因为它已经存在很长时间了。
- 文档齐全,易于学习。
- 提供简单的 Web 应用程序部署选项。
- 支持 Java 企业版。
- Coyote 引擎可运行多个 Java 企业应用程序,包括 Java Persistence API。
- 为用户提供额外的安全级别。
我们可以通过对比发现jetty似乎更轻量级,而tomcat更加的重量级,轻量的话一般是性能比较好,而重量的话功能会更加的完善和稳定,当然对于企业级应用来说肯定是追求性能和稳定同在,而他们两个的功能不同也同时注定了他们所采用的架构方式不同,这里就不进行展开细说,之后会慢慢的进行了解tomcat的架构设计,到时候会进行统一的对比,方便我们掌握他们的各自实现。
1.3 网络请求
这里简单的复习一下基本的网络请求是什么?可能我们都学过了很多的网络课程,可是当我们把知识当作文字记在脑中时仍然会觉得生硬,所以我们来采用类比的方法来理解请求。
1.3.1 网络协议
我们大概是从计算机网络这门课程中都已经了解过七层网络架构,这里我们来进行串一下TCP/IP的五层协议,这个比较适用于现在计算机软件应用。
应用层
应用层的分层主要为我们解决了数据获取和写入,这里的话我们可以通过应用层协议然后把我们需要的数据给封装或者是解封装。如果是我们进行寄信如果我们不进行封装信封,填写个人的信息,那么我们的信件肯定也是不能准确的投放到我们期望的目的地。
传输层
传输层的设计就涉及到了计算机的一些特性了,在计算机中如果向外进行通信的话就必须绑定一个对外的端口,这个端口就和这个应用进行了绑定,对于不同的协议也是可以绑定相同的端口的。这样的话我们只需要通过知道目标的IP和端口号我们就大概知道了它的具体位置,就相等于门牌号。
网络层
网络层的主要部分就是ip,网络数据报在不同的网段间进行传输,通过ip然后不断的在路由器之间传送,这里更像是送信时走过的马路,当然每个路由器就相当于是一个指示器,能够告诉我们如何能够最快的到达我们想要去的目的地。
数据链路层
数据链路层的最基本的功能是向该层用户提供透明的和可靠的数据传送基本服务。当请求到达了ip时,然后就需要通过将ip地址转化为mac地址,然后就等于说是到了小区需要然后转化为门牌号。
物理层
物理层则是将字节流转化为电气特性,然后进行传播,因为在具体的物理传输中是不能直接传输二进制的。
当然其中必然还有保证数据的顺序,和校验传输数据的完整性的算法,这些共同构成了我们目前所见到的TCP/IP协议簇。
1.3.2 HTTP协议
我们平常使用的最多的便是HTTP协议,它是一种传输协议具体的也经历了不断的迭代,从1.1到2.0再到3.0。不断的更新迭代让它逐渐的适应了现在的传输要求。
对于最早版本的HTTP协议在每发出一个请求就会新建一个tcp连接,毫无疑问这里是不合理的,到了http1.1则是通过请求头的keep-alive,然后达到复用tcp连接。
http1.1之前是采用明文传输,如果中间被其他人截获后可以很容易的查看到请求的参数以及一些私密的信息,于是对于重要的信息都推荐采用https的方式进行通信。
在这里可以看到阿里云的大部分接口已经是http2.0协议。
(这里插入一点之前的抓包就是通过抓取http的参数,然后定时或者不定时的进行请求接口达到签到的目的)在http2就改为了二进制的方式进行传输,只是不能直观的观察了,但是安全性的问题还是要依靠https,而且也进行了请求头压缩,将常用的请求头维护在两端,这样的话请求的数据量也会变少。
二、Servlet
我们来看一下Servlet4.0的规范,来观察一下这个Servlet到底是一个怎样的东西,怎么撑起了JAVA的web世界。
2.1 什么是Servlet
Servlet用我们自己的话来说就是一个入口JAVA类,它接收封装好的网络请求Request然后对外返回响应Response。当它进行配置后放入Servlet容器就可以进行正常的进行工作,它是后来JAVA Web框架的基础,构成了JAVA Web的基石。
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
2.2 Servlet容器
Servlet容器是Servlet的具体存放地,它可以控制每一个Servlet的声明周期,当一个请求到达时他负责将网络请求进行组装为可以识别的Servlet。当数据返回时他又负责装为可供发送的响应response。
2.3 Servlet容器初始化
Servlet的初始化随着程序的启动发生,只有当所有的Servlet初始化之后程序才对外提供服务,将对应的请求进行绑定到具体的Servlet,同时在初始化的时候会进行调用对应的init方法。
2.4 Servlet生命周期
通过init,service和destroy方法等进行控制。
2.5 Request
请求对象封装了来自客户端请求的所有信息。在HTTP协议中,此信息从客户端传输到HTTP报头和请求的消息体中的服务器。
public interface ServletRequest {
public Object getAttribute(String name);
public Enumeration<String> getAttributeNames();
public String getCharacterEncoding();
public void setCharacterEncoding(String env)
throws java.io.UnsupportedEncodingException;
public int getContentLength();
public long getContentLengthLong();
public String getContentType();
public ServletInputStream getInputStream() throws IOException;
public String getParameter(String name);
public Enumeration<String> getParameterNames();
public String[] getParameterValues(String name);
public Map<String, String[]> getParameterMap();
public String getProtocol();
public String getScheme();
public String getServerName();
public int getServerPort();
public BufferedReader getReader() throws IOException;
public String getRemoteAddr();
public String getRemoteHost();
public void setAttribute(String name, Object o);
public void removeAttribute(String name);
public Locale getLocale();
public Enumeration<Locale> getLocales();
public boolean isSecure();
public RequestDispatcher getRequestDispatcher(String path);
@Deprecated
public String getRealPath(String path);
public int getRemotePort();
public String getLocalName();
public String getLocalAddr();
public int getLocalPort();
public ServletContext getServletContext();
public AsyncContext startAsync() throws IllegalStateException;
public AsyncContext startAsync(ServletRequest servletRequest,
ServletResponse servletResponse) throws IllegalStateException;
public boolean isAsyncStarted();
public boolean isAsyncSupported();
public AsyncContext getAsyncContext();
public DispatcherType getDispatcherType();
}
可以看到主要是封装了方法如获取请求的路径、请求参数、请求类型等等,然后这样的话就可以被Servlet容器识别然后进行处理,这里的话是一个接口,后续的具体的协议实现是看我们使用什么样的应用层协议,比如他就有个具体实现HttpServletRequest,对应的也有HttpServletResponse和HttpServlet。
这里的话来提一下一个具体的URL构成.:
- domin域名构成了URL的第一层,它可以通过DNS服务器映射到我们的服务器的ip地址,由此便可以找到服务器的具体位置。
- port 端口号则是标明了我们需要和服务器的哪个应用进行通信,对于传输层的协议来说,端口号就是对应的应用身份ID。
- context Path上下文路径是针对服务器而言的,如果没有对项目进行配置的话默认是以项目名为主,主要为了区分不同的项目。
- Servlet Path Servlet主要是区分不同的请求处理,如通过对于路径名我们可以区分不同的Servlet操作,可以一一的进行映射。
- Parameter URL后的参数,主要是对Servlet传递信息。
2.6 Response
主要封装了对应的响应信息。
2.7 Filter
过滤器是可重用的代码片段,它可以用作书写统一的逻辑,可以更改初始的请求逻辑或者响应逻辑,我们可以用它来进行修改字符编码,或者实现一些我们自己的业务逻辑。
过滤器在首次启动就必须初始化完毕,因为后续的Servlet都需要经过它才能进行正常的业务处理。一般是通过链式调用,将过滤器链上的过滤器全部都需要运行一遍才能真正的走到Servlet。
这里就可以得到filter在JAVA Web的执行优先级还是蛮高的。
2.8 Session
超文本传输协议(HTTP)被设计为一种无状态协议。为了构建有效的Web应用程序,必须将来自特定客户端的请求相互相关联。因此Session就横空出世了,它是通过cookie进行跟踪会话机制,当客户端发送请求后,服务器会向客户端返回一个Session,之后的每一次请求都会携带上这个Session ID用作验证是否是同一个客户端,当然Session ID是可以复制的。
那么如果不支持Cookie的话我们该怎么办呢,我们也可以通过路径重写的方式,将对应的SessionID写入请求的URL里面,作为参数进行传递。
2.9 Event
可以用于事件的监听,对于Web应用的生命周期更好的掌控
2.10 Context
上下文信息,用于管理Servlet,可以用于获取当前应用的上下文,然后动态的进行添加Servlet等。
三、回顾
我们今天了解了tomcat的一些优势以及和其他web容器的对比,然后我们也进行大概的了解了Servlet在JAVA Web中的地位,至于有更多的知识本文并没有进行提出,我们还需要恶补操作系统,计算机网络等方面的知识,只有不断的强化自己,到了最后我们才能屡战屡胜。