您还未登录! 登录 | 注册 | 帮助  

您的位置: 首页 > 软件开发专栏 > 开发技术 > 正文

详解Java开发Web应用程序的底层原理

发表于:2019-12-16 作者:道以致远 来源:今日头条

前言

前面一篇文章,我从整个应用程序的整体以及跟运行环境的关系简单聊了一下我们现在常用的Spring框架的设计基础和原则,其中主要是控制反转和依赖注入,以及容器化编程等概念。

这里我不想去复述这些概念的定义,因为那些东西网上随便都能百度到,我想通过我的描述将这些概念串联起来,让大家更好的去立即它们知道为什么要这样去做,我们每天开发使用的框架到底是个什么东西,它的设计思想以及规范的由来。做到知其然还知其所以然,能够让我们在开发过程中更好的去使用它们,面对问题知道它大概的解决方向。

本文我想继续沿着前面的思路来谈谈基于Web的应用程序需要使用Spring框架的容器化管理开发相关的理解。

Web应用程序与Servlet规范

当然说起应用程序开发来,我们都熟悉,现在应用程序有很多种分类,最初的控制台程序,服务组件程序,到桌面应用程序,到基于HTTP访问协议的web应程序等。

其实它们的本质就是基于某种输入/输出过程处理的程序。比如我们最常见但是实际应用中很少的控制台应用程序,它就是基于标准的I/O实现类的应用程序,接收命令行作为输入流,控制台作为标准输出形式的应用程序。它的运行只需要有一个进程壳来构建输入和输出流即可。

而对于我们今天要详细谈的Web应用程序,其实它是起源于一种运行在操作系统上在组件程序,只不过它们的数据输入输出是基于网络数据流的。

网络基础

从基础的网络知识我们知道,网络上传输数据需要通过一个7层模型,也就是从最初的网络硬件抽象定义到最高级的应用程序这个层级穿透而来。

要将两台物理的机器连接起来,我们需要对两个机器进行标识命名,这些靠的是IP和端口,而网络链路上传输的数据都是字节数据流,要知道这些数据流是没有什么具体格式的,但是到了网络层时,我们必须要知道它来自哪里要发给谁,所以我们需要对其进行一定的格式限制,这种抽象是通过电报格式定义来完成的。

比如我们需要定义发送的长度,标记为,是否有顺序等,这些字节流就被包裹成一个个数据报文,然后我们必须定义每个发送端和接收端之间的约定,就是告诉对方我发送的是什么,你该如何接收它,比如多长是一个完整数据包,数据包的先后顺序等,这些都是在我们知道了两个通信店的IP地址以及如何连接也就是我们说的传输控制协议TCP的基础上我们定义了更高级的应用协议,比如HTTP,FILE,MAIL等协议,当然最常见的协议就是HTTP协议了。

HTTP协议

它是在基础的报文格式定义基础上的一个更高级的抽象,它能告诉通信双方我们通信的数据如何解析。就拿超文本传输协议来说吧,它规定了头信息和内容信息,它还规定了处理这些信息的方法以及结果反馈代码,这就是我们常说的GET,POST,DELETE,OPTIONS等,返回代码比如从100,到500系列,当然这些已经进入到了应用协议部分。

我们所有的网络应用程序都是基于点对点的通信的应用。也就是说要创建这样的程序我们必须首先标识出能够连接的两个点,首先是主机名或者IP地址,然后就是我们要连接的具体应用,它一般会体现在哪个端口上或者端口下面的哪个路径上。有了对等点的定义描述,我们就可以定义其控制传输的抽象,套接字概念。

编解码问题

其实质上就是创建一个输入输出流的通道,网络数据流都是通过Socket这个概念来定义和描述的。而我们编程,特别是Java的编程,我们只需要在我们应用程序所管理的空间中定义一个可以连接网络Socket的通道,同时在内存中划出一块缓冲区,让通道能够有可操作的空间,然后利用不同缓冲区之间数据流动的过程对数据进行相应形式的变化,比如最基础的是如何将网络传输的字节流,转变为我们高级语言定义高级数据类型的过程,这个过程通常被称为解码,同样当我们需要将应用程序能够理解的各种数据类型转变为可用通过网络传输给其它地方的字节流时,这个过程被称为编码。

因为硬件能够搞懂的目前就两种状态,这两种状态用数字表示就是二进制的0和1,所以我们使用的众多高级编程语言里,哪些复杂的数据类型都需要转变成二进制的字节形式才可以被CPU理解,被网络硬件传输。因此我们的编程不可避免的就需要去完成这种编码和解码处理。当然随着高级语言的不断进化,各类常用的处理都已经变身为各种语言标准的类库或者功能包了,我们只需要拿来用即可。除非你想编写自己的通信协议或者定义特殊的数据格式,否则对于编解码来说一般不会涉及到。

了解了所有应用程序都是对数据流的处理这个基础后,我们再来看Web应用程序,它是一种基于网络的服务和独立访问结构的应用程序,也就是我们常说的Server-Client模式。

关于Servlet

这里之所以定义出服务端和客户端其实主要还是一个功能上的区分,但是底层实质上还是两台计算机的连接,通过字节流交换数据,通过协议来规定传输控制和数据解码,而我们的web应用程序就是基于HTTP协议的网络应用程序,因为涉及到的网络处理,所以技术人员将有关网络处理部分独立出来规定了很多规范,比如端点描述规范,数据传输格式规范,如何利用所在计算机操作系统环境的设置的规范等,这些反应到Java编程里就是我们都熟悉的Servlet规范。

这个规范首先告诉我们基于Web的应用程序的基础网络部分需要在每台联网计算机上有一个角色来负责,我们称这个角色为容器,或者说是web服务器。

它就是要实现对计算机网络的标识,连接,规定解析数据格式等工作,当然后来我们将其发展成综合性的服务器,一边要处理HTTP协议,一边还可以通过一些接口更操作系统进行交互调用操作系统的功能组件来处理。比如网卡,文件的输入输出控制器等等。

我们可以简单的描述一下一个Servlet容器的实现功能,首先它需要对运行自己的主机信息有一个抽象,能够让运行的程序了解它以及使用它可以使用的资源。

然后,它需要将基于网络的字节流进行高级语言数据类型的转换,比如将基于字节流解析成遵循HTTP协议的数据格式,HttpRequest,HttpResponse以及HttpServletRequest,HttpServletResponse等。

同时将对于宿主服务器环境参数抽象后引入到该容器中用于跟我们的应用程序交互。所以只要实现了Servlet的规范,就可以作为操作系统和我们应用程序之间的媒介。

Servlet容器

市场上有许多成熟Servlet容器产品比如Tomcat,Jetty,Weblogic,Glassfish等。这里面有很多轻量级的,只负责将输入的网络数据流转换为我们应用程序能够理解和处理的数据形式,而这个过程都是通过创建输入和输出数据流的过程来完成的。有一些商业应用的实现附加的内容比较多,比如对系统环境资源的抽象继承,比如数据库连接资源,文件输入输出组件等。

我们开发的应用程序根据我们设计开发原则,我们首先将应用分解能功能组件,将每个功能组件设计成一个可以在容器中独立运行的组件,该组件就是HttpServlet请求处理组件。

我们会根据请求的目标地址来标记各种功能,然后将这些唯一的目标地址和HTTP方法来标识运行的目标组件,而这个组件可以通过容器来计算机环境进行交互。

所以Servlet的顶层抽象就是一个service方法,该方法的输入参数就是由容器进行封装过的请求体和回复体以及环境变量对象等。

当然我们会根据HTTP协议来具体的细化其支持的HTTP方法,所以我们可以来通过doGet,doPost等方法来完成具体的处理。

有了我们这样一个基础规范的功能实现,我们就有了一个可以包容和管理具体功能应用组件的容器,这个容器就是我们所说的web服务器。

如果你清楚了Servlet规范的本质就是对网络数据流的封装和编解码处理,你可以自己动手从基础的二进制数据流的封装和编解码转换开始设计自己的web应用服务器。

也就是去实现点对点的通信处理,这里说一下,目前的微服务架构的基础就是对web服务器基础网络实现的重新分解设计。

Servlet 3.0 引入了反应流概念,就是通过接收方控制来管理大批量数据流的输入输出。

Spring框架和Web应用设计

了解了上面有关Web应用程序的结构后,我们再来看看Spring框架在web应用程序开发中扮演的角色是什么。

我们知道Java企业级开发中有Java EE框架,其实就是基于Servlet容器来的,它只是将企业级应用开发的所有基础功能都组件化了,比如容器化依赖注入,JPA等,当然必须有匹配的Web应用服务器来支持其运行。

同样的Spring框架的核心部分就是组件容器,它的功能是通过更加有效更加轻量级的去组织和管理应用程序各功能组件。

其巧妙之处在于将整个组件设计成了一个Servlet组件实现,这就是Spring框架里最为核心的DispatchServlet,跟所有Servlet定义规范一样,我们需要用一个请求的目标路径来标识这个Servlet,然后让Servlet容器在启动时将它加载,并绑定到目标路径上,以此在一个对根目录请求的处理器中启动一个应用程序组件管理容器,并将其处理器handler实现成一个前端控制模式,负责对其根目录后的URL部分进行识别和匹配,以此来实现对Spring容器中负责处理后续URL资源的处理器的路由。

简单说来,就是当外部访问请求通过网络到达Web服务器时,会将其根据Servlet规范和HTTP协议将其解码成HttpServlet的请求和回复数据结构类型,然后解析其访问的目标资源URL,来匹配我们在Spring容器中注册的用于处理它的组件和方法名称,从而完成对该Servlet请求的处理。

由于现在我们开发应用程序时除了连续的文件上传下载处理外,大多都是将二进制转换为JSON数据格式或者XML格式,如此我们只需要在Spring容器中注册相应的处理组件即可。

总结

说到这里想说的东西还没说完,但是文章长度已经超出了预期,所以就此打住吧,只能在接下来另辟文章继续讲了。

本篇文章简单的讲了一下从Web应用程序的特点,以及能够辅助Web应用程序运行的基础容器服务规范,进而到了Spring框架的设计原则和结构实现设计。

这里希望能够带大家从Web应用程序有别于其他类型的应用程序的特点开始,到支持Web应用程序运行的Servlet规范实现,在到Spring框架应用在Web应用程序时扮演的角色等内容过了一遍。接下来我会继续沿着这个思路,讲一下MVC模式,以及反应流处理模式等内容。