![fef3eaedd304567845182d41f5ed1464.png](https://i-blog.csdnimg.cn/blog_migrate/9945377dc4c364633bd0a7f8a1df54b1.jpeg)
前言
前面我们对Web应用开发的底层技术做了一些串联,也就是从应用程序的本质出发来理解为什么我们的应用程序架构的演变。
特别是Spring框架的出现,它在Web应用开发中扮演的角色,特别是Servlet规范主导了整个Web应用程序的演化全过程。
本文我们接着上面文章,继续沿着Web应用程序底层数据流的处理和演变来串一下开发现代Web应用程序所需要的知识点和原理。
应用程序设计的隔离与通信
从我们开发应用程序的技术设计角度来说,由于计算机对于业务数据的呈现和业务逻辑的处理都是每次只能处理一部分的,这个过程中会后很多的处理频次和中间的数据状态需要保存如此以来,我们开发应用程序最基础的需求就是对不同数据的隔离存储和相互使用的通信联系的建立和控制。
也就是说我们应用程序使用的对象实例是有区域限制的,也就是可见性限制。因为我们知道,我们编程的本质就是对数据进行隔离和通信。
而在我们使用类似Java的高级语言开发应用时,Java语言就为我们提供了很多规范的定义,让我们能够实现对数据的封装分离,同时还能在某个特定的范围内进行通信交换。
其本质就是为数据的存储空间添加一个标记,使得引用和被引用的圈层之间相互隔离,同时又能通过某种地址表示获取到该数据。
这些就是高级开发语言中各类关键字的作用。
![4608a9baede23cf958b1d9e6bf14f0f8.png](https://i-blog.csdnimg.cn/blog_migrate/fab045e18c7a0572e611034191aa92c4.jpeg)
Web应用层级开发内容
在Web应用程序层级,我们在开发一个应用程序时,其实只是开发了该应用程序的具体数据处理部分,而哪些网络连接,数据解析以及跟操作系统交互部分都是web服务器应用来完成的。
所以严格来说,我们开发的应用程序只是涉及到业务的数据表达和逻辑的实现上,而没有去关注更为基础的网络连接,数据接收和发送以及中间调用的系统资源等。
可以说Web应用程序只是整个应用的一部分,或者说我们开发人员之编写了一个内容部分而外壳是有web服务器来负责提供的。这就要求我们在开发这类应用程序时,需要考虑web服务器为我们提供的环境接口以及web服务器对于能够在它上面运行的应用程序的规范和要求。
这也是Servlet规范中的主要内容,最初我们会将这种规范形象化为JSP,后来到JSF再到JSFX等。
当然这是对于处理内容表现上一些规范,如果我们不需要展现,那么可以直接使用二进制数据流,也可以使用定义的任何数据类型。
这取决于具体的应用环境和遵循的协议。
我们这里只说常用的基于HTTP的服务和处理。HTTP协议规定了每次传输的数据结构,以及在控制传输过程中常用的命令和回复代码以及内容表现形式,而它会抽象为我们编程的具体函数和方法,将其植入到Servlet规范的service()业务处理的入口方法里,这些可以具体看Servlet规范对于HttpServletXXX等的说明。
有了Servlet规范实现的Web服务器,我们就可以将具体的Web应用部署到该服务器上运行了。
为了让Web服务器知道它要管理和运行的应用程序,我们必须通过一个指定格式的文件web.xml来告诉它,该文件被称为应用程序在web服务器上的部署描述文件。
我们只需要将编写的应用程序内容按照该文件描述的格式去进行描述,Web服务器就能够识别它们,并将我们编写的内容跟服务器本身无缝连接成一个完整的web应用。
![196b3199edf58f569c8ac23938c6a823.png](https://i-blog.csdnimg.cn/blog_migrate/901abd1945c7022f4e557adb20603975.jpeg)
Web应用部署规范实现
跟我们电器跟电源之间的连接都需要有符合标准的电源插槽和插头一样,我们编写的应用程序跟Web服务器应用的连接也是标准的,在Spring MVC这个框架里,我们可以通过xml,annotation以及编程等方式来描述这些接口。
这里的注解(annotation)是高级语言编译器的一个新功能,它能够独立的读取和编译这些注解的内容,以便在具体编码过程中一些非业务逻辑的内容无法表现在程序的逻辑代码中,而以标注的形式提供。在Spring MVC 2.5以后的版本里,这被称为注解编程方式。
我们可以使用这种方式将一些对组件的说明和定义分布到整个应用程序的代码中,而不需要集中的按照XML格式写到一个列表里。
Spring MVC框架组件
关于Spring MVC框架,其实就是对于一个应用程序的编写来说,我们需要涉及到跟容器的交互,接收数据,业务逻辑处理实现,将数据以某种数据格式发送展现给请求者等。
根据工程学的知识,要想能够便于管理,我们不能将这些功能性内容实现和非功能性内容实现混合在一起,同时为了便于管理有人就提出了一个实现模型,就是模型-视图-控制器,有控制器C负责非功能性流程控制,而模型M来处理数据实现,视图V来提供处理结果的展现,这就是著名的MVC模型。
它的使用无法就是为我们的应用程序编写在不同作用组件管理上做一下分类,将类似功能的组件内容定义到同一分类里,便于管理,同时能够很好的进行分类管理,不至于太混乱。
其实这些所有的MVC组件都是一样的东西,只是功能不同而已。为了划分这些分类我们需要为它们定义标识符,也就是做个标记。
最开始的思路是按照工程目录的文件夹路径来分类管理,后来引入了描述文件,比如xml或者YAML格式等,现在流行的是注解模式,跟所有的注解定义一样只是定义了一个标记。
所以我们可以为MVC三类组件分别定义不同的标记,只为了便于管理。
说起Spring容器和Spring MVC模式的关系,简单说MVC是对应用程序组件的功能性分类标识,在Spring容器看来他们都是多了个标签符合的容器管理组件而已。
一样遵循相关的受Spring容器管理组件的规范。
![8b5f15b5a6201eb0ad02a47a42570e50.png](https://i-blog.csdnimg.cn/blog_migrate/18f3fb7be55df7291a3ec3cc64e6cb1c.jpeg)
Servlet规范在Spring MVC框架中的实现
从Web服务器级别来看Spring容器,其实就是一个特定的Servlet实现。
最初的时候,我们直接通过编写一个个Servlet组件来为应用程序提供数据处理服务,现在我们将Spring容器定义成一个特定的Servlet,并且结合统一资源定位符和Servlet组件要处理的目标资源路径
一起来定位最终的请求处理组件。我们从Web应用程序的部署描述文件Web.xml的Servlet描述可以看到,我们可以定义多个Servlet组件来处理不同的路径上的请求。
这是Web服务器级别的Servlet组件,现在由于Spring容器和Spring MVC框架的引入,我们不再直接基于Web服务器来编写一个个Servlet组件提供服务了,而是通过预定义一个服务器路径,然后在该路径下提供多个后续不同资源定位符的逻辑处理组件。
从而使得我们可以将特定目录内容交给一个复杂应用程序来处理。这个复杂应用就是基于Spring容器管理的多个组件实现。
DispatcherServlet组件
要做到这一点,我们首先要在Web应用程序的部署描述中定义这个入口Servlet,而这个Servlet一般由Spring框架提供的特殊实现,DispatcherServlet组件。
它的任务就是作为一个Servlet组件部署到Web服务器中,在服务器启动时将它跟Web服务器连接起来,从而能够成为为其映射的路径请求提供处理。
如果按照传统的Servlet组件处理具体应用方式,这里只有一个Servlet组件实现显然是无法提供多种请求处理服务的。所以,我们在这里引入了一种前端控制模式实现。
即在该DispatcherServlet的实现逻辑中增加了统一资源定位列表和对应请求处理器Handler定义列表,对每个访问该路径的请求截取其所访问的资源定位符进行比较和路由处理。
从而将该请求数据发送给绑定了该资源定位URL部分的处理器组件上,从而将请求路由给它处理。这就是一个路由器的实现,当然它还包括很多过滤和数据转换处理,以及对于资源定位部分的匹配规则和算法实现等。
![2bd4bf506e1e4c54d335edac3c78fb07.png](https://i-blog.csdnimg.cn/blog_migrate/5f40bc09b962ee4d7ce57bf3f2852336.jpeg)
Spring容器管理组件
总体上使用Spring容器和Spring MVC来实现一个Web应用程序来说,需要将我们应用程序的所有组件都定义和声明为遵循Spring容器组件管理规范的类定义,然后在Web服务器需要读取的每个Web应用程序的部署描述文件web.xml中提供的定义声明,这个Servlet应该是DispatcherServlet,并将其绑定在我们的应用程序的根路径上。
使用过Spring MVC框架的人都知道Spring还提供一个符合Servlet规范的ContextLoaderListener实现,它用来在服务器启动过程中加载资源内容。
我们会将Spring容器的内容通过这个监听器接口来导入到Web服务器中使之成为该Web应用程序的可用资源。
而在DispatcherServlet被调用后,它会将Spring容器的配置信息读入并初始化以提供各类实例依赖项。也就是说在Web服务一启动这些资源内容就会被放入到某个应用程序上下文中,然后DispatcherServlet会用这些资源来初始化Spring容器定义组件实例,完成Spring MVC框架的实现。
当然现代应用程序开发的内容相当复杂,需要使用到很多外部系统资源或者第三方软件资源,比如数据库连接,Java的目录和接口资源等。
我们过去传统开发会将它根据Servlet规范实现成有状态,无状态,会话等组件,现在有了Spring容器,我们完全可以将它们按照Spring容器能够管理组件的规范来封装和定义。
从而让这些资源能够作为Spring 容器管理的组件使用,并受到Spring容器的全生命周期管理。
而Spring MVC整体会嵌入到一个Servlet实现中,从而在一个特定的目录下对其所有请求进行分类处理。也就是我们前面所说的通过路由器的实现,将不同的网络请求根据资源定位符来映射到具体的处理组件控制器部分。
由它负责协调数据处理,结果展示模板解析,以及相关的数据持久化处理等。总之MVC框架之上一个功能意义上的分类,在技术上只是对众多不同的应用程序专用组件进行标签化分类而已。
![d2281d7d7d0efcfc429979bb35a84290.png](https://i-blog.csdnimg.cn/blog_migrate/52769a86ea33843993cfc45c02649d49.jpeg)
Web应用开发与微服务
使得这些功能类似的组件受到统一的管理,我们开发人员在工程目录组织和编译器处理时方便,其实它们本质上都是装在容器化的依赖注入的组件。
随着应用程序架构的不断演变,现在由于云计算和分布式存储技术的发展,微服务架构成为了主流,它能很好的克服过去我们开发的传统的巨型化应用的很多弊端,比如可靠性,可维护性,容错性等方面的缺陷。
就是将原来的应用程序从功能进行分类封装,同时在架构上做垂直化分解,特别是虚拟机容器化技术的发展,为在同一台主机上运行多个容器提供了可能,也就是说同样的服务组件可以在同一台机器上独立运行多个而由于容器化的隔离相互不会产生干扰。
如此依赖过去传统开发的应用程序构成组件是运行在同一个Web服务器上,各个功能之间的相互依赖和调用都是在同一个依赖管理容器中,比如同一个Spring 容器,所以它们是运行在同一个进程中的多个线程之间的调用和访问。
而到了微服务时代,不同功能的组件可能会垂直化成一个独立的应用程序,功能单一的服务程序,它会以独立进程的形式运行在主机上,如此以来我们在去组织这些独立的进程构建综合型应用服务时,其相互之间的依赖调用就成了跨进程之间的或者跨网络之间的通信了。
这种通信需要依靠进程间调用IPC或者网络对等机器之间的连接和访问最常用的是基于HTTP的调用。
从传统的Web应用程序到现在流行的微服务架构的变化其实就是一个从线程间调用到进程间或者跨网络之间通信的实现转变,这样带来的好处是我们的服务的弹性和可用性以及弹性大大增强。
而缺点在于开发的复杂程度极度的增大,因为它需要的技术支持更加细化和庞杂,比如网络通信知识,容器化和管理编排知识,进程间调用的协议以及编解码,跨网络调用的稳定性处理,安全以及数据分布式存储等一些列的技术。
总结
虽然微服务涉及到的新技术很多,但是其底层的核心逻辑还是对于网络数据流的处理,以及如何在对等点之间建立稳定的连接,在服务器不稳定时如何通过熔断或者快速中断机制来保证服务的稳定提供等。
后面我将另找时间来逐步说一下微服务架构底层实现的东西。