成功运行一个简单的后端应用程序后,接下来介绍后端应用程序的工作原理。
一个Java后端应用程序要想运行起来需要两步,第一步是搭建Web应用服务器,为后端应用程序提供运行环境,第二步是把后端应用程序放到Web应用服务器上。
相应地,后端应用软件的工作原理我们也分为两部分来介绍。一部分是Web应用服务器运行后端应用程序,介绍Web应用服务器与后端应用程序的关系;另一部分是后端应用程序处理接口请求,介绍后端应用程序与接口请求端(如网页、App等)的关系。在介绍这两部分内容之前,我们先介绍一下Java程序的运行原理。
注意:本小节默认以Tomcat作为Web应用服务器软件,以Java作为编程语言,以Spring Boot作为基础框架。在介绍原理时会省略很多内部细节,我们只需要大体了解即可。
1.Java程序运行原理
编译型语言通过专门的编译器,一次性地将源代码编译成可执行文件(机器码),可执行文件可直接运行在特定的平台上。由于可执行文件(机器码)是根据特定平台编译而成的,所以运行效率较高,但是不能跨平台使用。比较流行的编译型语言有C和C++等。
解析型语言不需要编译,但是在每次运行的时候都需要解析器把源码翻译成机器码,即每个运行程序的机器都需要安装一个解析器,解析器会根据自身平台把源码翻译成对应的机器码。解析型语言具有跨平台性,但是运行效率不高(每次运行都需要翻译成机器码)。比较流行的解析型语言有Python、Ruby和JavaScript等。
编译型语言和解析型语言的对比如图4.29所示。
而Java比较特别一些,Java既是编译型语言,又是解析型语言,因为Java既需要编译器又需要解析器。Java具备跨平台特性的同时,也比传统的解析型语言运行效率要高。Java编写的源码经过编译器编译之后,转换成.class文件(字节码,一种Java独有的源码与机器码之间的格式)。这些.class文件中的字节码在运行时需要解析器把字节码翻译成机器码才能运行。Java的编译运行过程如图4.30所示。
注意:一般情况下,Java源码编译输出的是.jar文件,而.class文件是.jar文件的主要部分。这里为了讲解方便,省去了对.jar文件的描述。
Java的编译器和解析器就是在4.1.2小节搭建Web应用服务器中提到的JDK,想要编译或者运行Java程序都需要安装JDK。JDK的内部结构如图4.31所示,它包含一些开发工具和JRE(Java Runtime Environment,运行环境),其中开发工具里有编译器,而JRE是运行Java程序的环境。JRE包含JVM(JavaVirtual Machine,Java虚拟机)和一些基础类库,其中JVM包含解析器,负责翻译字节码等工作,而基础库类是Java调用操作系统功能的桥梁。
注意:如果只需要运行Java程序,那么可以单独安装JRE。JDK 9版本发布以后,不再提供单独的JRE安装包。由于引入了新技术,JDK 9及后续版本的内部也没有了JRE(可以手动生成),而JVM是仍然存在的。这是因为JRE在运行Java程序时会加载所有的基础类库,这样比较损耗资源,而JDK 9及后续版本在运行程序时是按需要加载基础类库的。
2.Web应用服务器运行后端应用程序
本小节以Tomcat作为Web应用服务器软件进行说明。Tomcat本身是一个Java程序,启动Tomcat服务相当于启动一个Java程序。那么,Tomcat是怎么运行后端应用程序的?一个Java程序怎么运行另外一个Java程序呢?
首先,在Tomcat中运行的后端应用程序是.war文件而不是.jar文件。.war文件与.jar文件不同,.war文件是Web模块,其内部除了编译好的.class文件、依赖包和配置文件以外,还可以包含网页资源(HTML、CSS文件等)和JSP动态网页等。.war文件一般需要依赖Tomcat等Web应用服务器软件才能运行。
以4.1.3小节构造一个简单的后端应用程序中的demo.war为例,Tomcat运行demo.war其实不是一个Java程序运行另外一个Java程序的关系,而是一个Java程序使用编译好的.class文件的关系。更具体地说,当demo.war放到Tomcat的webapps文件夹中后,Tomcat会自动把demo.war解压成demo目录。解压完成后,Tomcat会对demo进行解析并加载相关的.class文件。当接收到请求时,Tomcat会调用对应的接口函数(TestController.java文件中的方法,见代码4.11),经由这些代码处理后再将结果返回。Tomcat运行后端应用程序的工作原理如图4.32所示。
说明:Tomcat加载并引用.class文件利用了Java的反射机制。一般情况下,Java程序引用类文件只能在编写代码时通过import引用其他类文件,而Java反射机制是允许在运行状态中通过给定类的名字加载指定类文件的。
Tomcat是通过图4.21中ServletInitializer这个固定类名加载相关文件的。
最后值得一提的是,Tomcat运行后端应用程序的工作原理其实是非常复杂的,特别是对相关文件加载的机制,本小节只对其做了最简单的陈述,有兴趣的读者可以通过官方文档和开源代码进行更深入的研究。
3.后端应用程序处理接口请求
发送一个请求至少需要明确4个部分:请求的URL、请求方式、请求数据的格式和请求数据。以4.1.3小节构造一个简单的后端应用程序中的接口一为例,以Postman为测试工具,发送请求的设置如图4.33所示。
注意:当请求方式为GET时,则请求数据一般只能写在URL里,如4.1.3小节构造一个简单的后端应用程序中的接口二。
由图4.33中请求的URL可知,请求是基于HTTP发送的。HTTP的通信过程如图4.34所示,其中,不是每次请求都会做一次连接的建立与断开,存在多次请求会共用一个连接通道的情况,这与HTTP版本和相关设置有关。
注意:接口请求一般是使用HTTP或HTTPS。HTTP是TCP/IP的应用层协议,也就是说,HTTP其实只是在TCP/IP之上做了规则限定和封装,其底层技术还是TCP/IP的相关技术。而HTTPS只是在HTTP的基础上做了通信加密,暂且不对其进行介绍。
在图4.33所示的请求例子中,客户端会以URL的IP地址和端口(127.0.0.1:8080)与Web应用服务器建立连接。建立连接之后,客户端会把剩下的信息(URL剩下的部分、请求方式、请求数据的格式、请求数据)按照规则放到报文里,再把报文发送到Web应用服务器上。发送的报文如代码4.14所示。其中,报文由三部分组成,分别是请求行、报文头信息和报文体。
·请求行:是报文的第一行,其由三部分组成,分别是请求方法、请求URL剩余的部分(除协议、IP地址、端口外)和HTTP版本。
·报文头信息:其范围是报文的第二行到空行。报文头可以设置多个属性,其作用是记录相关的请求信息。其中,Conten-Type属性对应的是请求数据的格式。
·报文体:其范围是空行到最后,对应的是请求数据。需要注意的是,当请求方式为GET时,一般不使用报文体。因此4.1.3小节中的接口二的请求参数只能写在URL中。
代码4.14 接口一的请求报文
POST /demo/test/test HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: text/plain
{
"language":"chinese",
"text":"你好,世界"
}
当Web应用服务器接收到请求的报文后,会对报文进行解析并转换成对应的Java对象。Web应用服务器会根据报文的请求行(POST/demo/test/test)找到对应的后端应用程序并调用相应的处理函数。
其中,请求行(POST/demo/test/test)会被分成两段(/demo和POST/test/test)处理,Web应用服务器会根据第一段(/demo)内容找到对应的后端应用程序,demo对应的是demo.war文件名。Web应用服务器会根据第二段(POST/test/test)内容调用后端应用程序对应的处理函数,后端应用程序对应的标记如代码4.15所示,其中,@RequestMapping("/test")标记了Controller的路径,@RequestMapping(value="/test",method=RequestMethod.POST)标记了对应方法的路径和请求方式,函数create()的参数String requestParam会被自动注入请求的数据(报文体)中。
说明:Java中以@开头的是Java注解,也称为Java标注,其相当于一个标签。@Request-Mapping、@Controller是Java Servlet标准中定义的注解。
代码4.15 接口一的代码
…
@Controller
@RequestMapping("/test")
…
@RequestMapping(value="/test",method = RequestMethod.POST)
public JSONObject create(@RequestBody String requestParam) {
…
}
…
当代码4.15的处理函数被执行完毕之后,会把结果返回给Web应用服务器,Web应用服务器会把返回的Java对象转换成HTTP报文,再把报文发送给客户端。返回的报文如代码4.16所示。其中,报文由三部分组成,分别是状态行、报文头信息和报文体。返回的报文在Postman中如图4.35所示。
·状态行:是报文的第一行,其由三部分组成,分别是HTTP版本、状态码和状态码描述。状态码及其信息一般是由Web应用服务器自动填充的,如状态码为200,即为成功,状态码为404,即为无法寻找对应资源等。当然,后端应用程序也可以对其进行修改。
·报文头信息:其范围是报文的第二行到空行。报文头可以设置多个属性,作用是记录相关的请求信息。其中,Conten-Type属性对应的是请求数据的格式。后端应用程序也可以添加一些自定义的属性。
·报文体:其范围是空行到最后,对应的是后端应用程序的处理函数返回的结果。
代码4.16 接口一返回的报文
HTTP/1.1 200 OK
Date: Tue, 31 Mar 2020 10:59:51 GMT
Content-Type: application/json
{"message":"你好,世界"}
以上介绍了后端应用程序的工作原理,当然这只是一些表面的认识,还有很多内容没有铺开陈述。这是因为在实际项目开发过程中,无论是HTTP请求还是Web应用服务器软件,都是现成的工具,我们多是去使用它们而不是去改造它们,因此对原理的了解不需要完全透彻,具体的细节可以等问题出现时再去了解。