之前的两篇的文章已经大概的带我们了解了tomcat的一些基本的操作,比如从零搭建我们自己的调试环境以及官方文档构建的方式,接下来的话,我将带大家来了解一下tomcat的一些基础知识,这些基础知识将以问题的方式抛出,然后引起我们自己的思考。
这一部门我们从tomcat的产生来进行讨论,主要的是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的默认嵌入性服务器。(个人看来,这里有利也有弊,虽然它方便了我们的日常开发工作,但是也让我们对于这个软件的认知变得更加的模糊,只需要编辑配置文件即可,面向配置文件编程。)
在我们的个人认知中,可能我们现在比较常用的是tomcat,可是在之前也有一个和他性能相近的web容器,它就是Jetty。
Jetty 提供 Web 服务器和 servlet 容器,此外还提供对 HTTP/2、WebSocket、OSGi、JMX、JNDI、JAAS 和许多其他集成的支持。这些组件是开源的,可以免费用于商业用途和分发,并且还可以作为许多框架、云服务、应用程序服务器和设备的嵌入式工具。
Jetty的特性
我们可以通过对比发现jetty似乎更轻量级,而tomcat更加的重量级,轻量的话一般是性能比较好,而重量的话功能会更加的完善和稳定,当然对于企业级应用来说肯定是追求性能和稳定同在,而他们两个的功能不同也同时注定了他们所采用的架构方式不同,这里就不进行展开细说,之后会慢慢的进行了解tomcat的架构设计,到时候会进行统一的对比,方便我们掌握他们的各自实现。
这里简单的复习一下基本的网络请求是什么?可能我们都学过了很多的网络课程,可是当我们把知识当作文字记在脑中时仍然会觉得生硬,所以我们来采用类比的方法来理解请求。
我们大概是从计算机网络这门课程中都已经了解过七层网络架构,这里我们来进行串一下TCP/IP的五层协议,这个比较适用于现在计算机软件应用。
应用层
应用层的分层主要为我们解决了数据获取和写入,这里的话我们可以通过应用层协议然后把我们需要的数据给封装或者是解封装。如果是我们进行寄信如果我们不进行封装信封,填写个人的信息,那么我们的信件肯定也是不能准确的投放到我们期望的目的地。
传输层
传输层的设计就涉及到了计算机的一些特性了,在计算机中如果向外进行通信的话就必须绑定一个对外的端口,这个端口就和这个应用进行了绑定,对于不同的协议也是可以绑定相同的端口的。这样的话我们只需要通过知道目标的IP和端口号我们就大概知道了它的具体位置,就相等于门牌号。
网络层
网络层的主要部分就是ip,网络数据报在不同的网段间进行传输,通过ip然后不断的在路由器之间传送,这里更像是送信时走过的马路,当然每个路由器就相当于是一个指示器,能够告诉我们如何能够最快的到达我们想要去的目的地。
数据链路层
数据链路层的最基本的功能是向该层用户提供透明的和可靠的数据传送基本服务。当请求到达了ip时,然后就需要通过将ip地址转化为mac地址,然后就等于说是到了小区需要然后转化为门牌号。
物理层
物理层则是将字节流转化为电气特性,然后进行传播,因为在具体的物理传输中是不能直接传输二进制的。
当然其中必然还有保证数据的顺序,和校验传输数据的完整性的算法,这些共同构成了我们目前所见到的TCP/IP协议簇。
我们平常使用的最多的便是HTTP协议,它是一种传输协议具体的也经历了不断的迭代,从1.1到2.0再到3.0。不断的更新迭代让它逐渐的适应了现在的传输要求。
对于最早版本的HTTP协议在每发出一个请求就会新建一个tcp连接,毫无疑问这里是不合理的,到了http1.1则是通过请求头的keep-alive,然后达到复用tcp连接。
http1.1之前是采用明文传输,如果中间被其他人截获后可以很容易的查看到请求的参数以及一些私密的信息,于是对于重要的信息都推荐采用https的方式进行通信。
在这里可以看到阿里云的大部分接口已经是http2.0协议。
(这里插入一点之前的抓包就是通过抓取http的参数,然后定时或者不定时的进行请求接口达到签到的目的)在http2就改为了二进制的方式进行传输,只是不能直观的观察了,但是安全性的问题还是要依靠https,而且也进行了请求头压缩,将常用的请求头维护在两端,这样的话请求的数据量也会变少。
我们来看一下Servlet4.0的规范,来观察一下这个Servlet到底是一个怎样的东西,怎么撑起了JAVA的web世界。
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();
}
Servlet容器是Servlet的具体存放地,它可以控制每一个Servlet的声明周期,当一个请求到达时他负责将网络请求进行组装为可以识别的Servlet。当数据返回时他又负责装为可供发送的响应response。
Servlet的初始化随着程序的启动发生,只有当所有的Servlet初始化之后程序才对外提供服务,将对应的请求进行绑定到具体的Servlet,同时在初始化的时候会进行调用对应的init方法。
通过init,service和destroy方法等进行控制。
请求对象封装了来自客户端请求的所有信息。在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构成.:
主要封装了对应的响应信息。
过滤器是可重用的代码片段,它可以用作书写统一的逻辑,可以更改初始的请求逻辑或者响应逻辑,我们可以用它来进行修改字符编码,或者实现一些我们自己的业务逻辑。
过滤器在首次启动就必须初始化完毕,因为后续的Servlet都需要经过它才能进行正常的业务处理。一般是通过链式调用,将过滤器链上的过滤器全部都需要运行一遍才能真正的走到Servlet。
这里就可以得到filter在JAVA Web的执行优先级还是蛮高的。
超文本传输协议(HTTP)被设计为一种无状态协议。为了构建有效的Web应用程序,必须将来自特定客户端的请求相互相关联。因此Session就横空出世了,它是通过cookie进行跟踪会话机制,当客户端发送请求后,服务器会向客户端返回一个Session,之后的每一次请求都会携带上这个Session ID用作验证是否是同一个客户端,当然Session ID是可以复制的。
那么如果不支持Cookie的话我们该怎么办呢,我们也可以通过路径重写的方式,将对应的SessionID写入请求的URL里面,作为参数进行传递。
可以用于事件的监听,对于Web应用的生命周期更好的掌控
上下文信息,用于管理Servlet,可以用于获取当前应用的上下文,然后动态的进行添加Servlet等。
我们今天了解了tomcat的一些优势以及和其他web容器的对比,然后我们也进行大概的了解了Servlet在JAVA Web中的地位,至于有更多的知识本文并没有进行提出,我们还需要恶补操作系统,计算机网络等方面的知识,只有不断的强化自己,到了最后我们才能屡战屡胜。