上篇笔记学习了下如何从零到一搭建 SpringBoot 后端项目,在实现代码的部分发现有很多Java 的注解,想要搞清楚这些注解的目的、以及这个项目是怎么跑起来的?SpringBoot 到底是个啥?
这篇文章就是记录一下认识这个新建后端项目的过程。
当 SpringBoot 项目运行起来之后,我们会在终端看到几行日志,如下
[main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
[main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
[main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.70]
这里说启动了 TomCat,TomCat 是啥?这里引出了一系列的基础概念
# 一些基础概念
# TomCat
Tomcat 是一个开源的 Java Servlet 容器,也是一个用于构建和运行 Java Web 应用程序的 Web 服务器。它由 Apache 软件基金会开发和维护,是一个非常流行的用于部署和管理 Java Web 应用程序的工具之一。
那问题来了?Java Servlet 是啥?
# Java Servlet
Java Servlet(简称 Servlet) 的官方定义是用Java (opens new window)编写的服务器 (opens new window)端程序 (opens new window)。其主要功能在于交互式地浏览和修改数据,生成动态 web 内容。**本质上其实就是一个遵循 Servlet 标准开发的 Java 类,**我自己理解 Servlet 标准有点类似编程中的「接口」的概念,实时上真实的编程世界也是这样做的
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
Servlet 有生命周期的概念,在生命周期内,构造初始化(init)和释放(destory)对象的方法都只调用一次,业务方法(service)会执行很多次。我理解其实就是服务器启动之后,可以不断的接受来自客户端的请求,当服务器关闭后就不再接收请求了。
Servlet 是由服务器调用的,运行在服务器端。Servlet 带给我们最大的作用就是能够处理浏览器带来 HTTP 请求,并返回一个响应给浏览器,从而实现浏览器和服务器的交互。
后续提到的 HTTPServlet
,它其实就是继承了 Servlet,实现了 service
方法,根据 HTTP 请求方法(GET/POST)等来执行不同的逻辑。
贴一段 HTTPServlet
实现 service 的方法,以及 HttpServletRequest
的部分定义,如下
/// HTTPServlet.clas
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
this.service(request, response);
}
//
public interface HttpServletRequest extends ServletRequest {
String getMethod();
String getHeader(String var1);
String getPathInfo();
String getQueryString();
...
}
Web 服务器已经把 HTTP 请求(如下一段纯文本)解析成了 HttpServletRequest
对象,让我们方便在 service
业务方法里面操作,我们可以在 service
方法里面加入自己的逻辑,来根据收到的请求返回不同的数据。
//HTTP 请求样例
GET /servlet/hello?username=fanthus HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Language: zh-CN,zh;q=0.9
Cookie: Hm_lvt_82116c626a8d504a5c0675073362ef6f=1585269393,1585357421,1586488037,1586738782
# Tomcat 和 Servlet
Servlet 容器和 Web 应用服务器其实是一个东西,而 TomCat 算是 Web 应用服务器的一种,所以 Tomcat 定义里会有「Tomcat 是一个开源的 Java Servlet 容器」这句话。
具体实现上是 Tomcat 管理了 Servlet 的生命周期,是 Tomcat 通过根据反射的方式创建了 Servlet 类实例,然后在接收到请求时执行 Servlet 业务方法(service),关闭 Tomcat 的时候调用 destroy 方法,释放当前对象占用的资源。
我们目前的项目里 SpringBoot 是基于 Tomcat Web 服务器的,但是似乎没有看到项目和 Servlet 的关系,等等,SpringBoot 究竟是什么东西?
# Spring Boot
Spring Boot 可以轻松创建独立的、生产级的基于 Spring 的应用程序,让用户可以一键安装运行。
那么问题又来了,Spring 是什么?
# Spring
Spring 框架是 Java 平台的一个开源的全栈应用程序框架和控制反转容器实现,一般被直接称为 Spring。该框架的一些核心功能理论上可用于任何 Java 应用。我自己感觉 Spring 就是一个通用的 Java 库,开发任何 Java 相关的程序都可以用 Spring 框架。
那 Spring 和我们进行的后端应用开发是什么关系?这里需要提到 SpringMVC..
# SpringMVC
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。
我们之前知道 Servlet 是处理来自客户端的请求的,Servlet 基于用于处理请求和响应的低级 API。 Spring MVC 框架旨在使构建处理 HTTP 请求和响应的 Web 应用程序变得更加容易。
如果用 Servlet 来编写 Web 应用程序,我们处理的细节很多,比如验证请求、JSON 的请求/响应正文、表单绑定等等。我们需要编写大量实用程序代码来支持 Web 应用程序。对于我这个 iOS 开发者而言,就好比我们开发客户端应用的时候,一般不会使用系统自带的网络请求库,而是使用 Alamofire 这类第三方网络请求库一样。
# Spring Boot vs Spring vs SpringMVC
总结一下这三者的关系
Spring 是通用的 Java 工具库。 Spring MVC 是 Spring 框架中的一个 Web 模块,一开始就包含在 Spring 框架中,同时也是基于 Servlet 的的 Web 框架,提供基础的服务。
Spring Boot 是为了简化 Spring 开发而产生的脚手架。正常 Spring 配置的东西很多,Spring Boot 提供了可视化的一键安装的方式,简化整个配置流程,当然理论上也可以不通过 Spring Boot 来配置应用程序。Spring Boot 也提供了 SpringMVC 框架的一些自动配置,参考这里 (opens new window)。
回到文章的主旨,认识上一章创建好的 SpringBoot 的后端项目(Web 服务器程序),回忆一下之前创建项目的时候,有个步骤是选择依赖,当时我们勾选的是 Spring Web。这个依赖的解释是「使用 Spring MVC 构建 We(包含 RESTful) 应用程序,并且使用 Apache TomCat 作为默认的内置(servlet)容器」所以项目底层是使用 Spring MVC Web 框架。
我们也可以在项目里的 pom.xml 依赖管理文件里看到项目的依赖,spring-boot-starter-web
这个依赖就是之前添加的 spring web
依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
# 理解 SpringMVC
Spring Web MVC 的官方文档在这里 (opens new window)可以查看。具体内容很多,这里不深入原理细节,还是结合项目来理解一下 Spring MVC 到底在项目中是如何工作的?
# 先理解 MVC
之前做客户端的时候,写过一篇关于 MVC 的文章《MVC和MVP的简单理解 (opens new window)》,传统的 MVC 架构如下,本质上 MVC 是逻辑、数据、界面显示分离的一套软件设计规范。
各个端的职责
- Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
- View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
- Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
# 说回 Spring MVC
Spring Web MVC 就是实现了Web MVC 设计模式轻量级 Web 框架,它是基于请求驱动的,并且也使用了前端控制器模式来进行设计,再根据请求映射规则分发给相应的控制器进行处理。
具体的请求处理流程在官方文档的 SpringMVC → 1.1.5 Processing (opens new window) 这里,这里先不叙述了。
阿里云社区上的这篇文章 (opens new window)对 Spring Web 项目介绍的特别好,这里直接引用如下
整个 Spring Web 工程将主要分为5个模块:view、controller、service、model和AOP,这些模块是具有层级关系的,view 最靠近浏览器端,所以在层级上面属于最上层,浏览器发送请求并由controller 响应请求并调用底下的 service,由 service 层去操作数据,controller 将得到 service 的返回结果并将数据传递给 view 层,最终 view 层输出给浏览器,而 AOP 将作为通用模块使用。用图说明如下:
在上面的说明中 controller 层应该是非常轻量的,因为它只负责转发请求,不做具体的业务逻辑。model 层是涉及到数据库相关操作的,这里不多解释。
# 结合项目说明
为了方便对照说明,贴一张上一篇笔记的项目图
# 项目目录
回到我们的项目里,我们创建对应路径响应的时候,创建了一个名字为 controller 的 package,在项目下创建了一个 HelloController 的文件。
这个 Controller 对应了 MVC 中的 Controller 这个概念,只不过我们项目比较简单,没有涉及到 model 和 service 层,而且上面也没有涉及到 view 层。
# 项目注解
controller 实现中涉及到的三个注解是 @RestController
以及 @RequestMapping("/hello")
。这三个注解都是 SpringMVC 框架提供的。
@RestController
是从Spring 4.0以后产生的,用来将 json/xml 数据发送到前台页面,而不是返回视图页面。
在此之前使用的注解是 @Controller
,如果上面注解修改为 @Controller
则再请求 /hello
路径网页会报错如下,本质原因是 @Controller
返回的是视图页面,这时候必须配合 @ResponseBody
注解才能达到 @RestController
的效果,所以现在都直接使用 @RestController
。
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Sep 14 19:52:00 CST 2023
There was an unexpected error (type=Not Found, status=404).
@RequestMapping("/hello")
这个注解用来映射请求,也就是通过它来指定控制器可以处理哪些URL请求。这个注解可以使用在Controller层的类或者方法上。
比如这里添加了 /hello
请求路径,表示这个方法可以处理这个路径,请求打过来的时候就会执行此方法,我们在方法里做我们想要做的事情。
回到我们最开始的 Servlet,其实这个方法做的事情看起来和 Servelet 提供的 service 方法很像,只不过经过了 Spring MVC 的层层包装,让实现变得更加简单。
还有更高级的 @GetMapping(”路径信息”)
,@PostMapping("路径信息")
这种注解,它是对 @RequestMapping
的更高级别的封装形式,明确了当前方法能处理的 HTTP 请求方法类型是 Get 还是 Post。
这里只是最简单的介绍,更多的注解在使用中慢慢体会了。
# 总结
以上就是本文的全部内容,介绍了后端项目用到的框架以及运行起来的原理,介绍了 SpringMVC 框架对应的项目目录,以及一些注解的使用,非常粗浅,作为本人学习过程中的笔记整理,希望对你有帮助。
接下来尝试在项目中连接数据库,相关笔记在这篇文章
参考地址:
- Java Servlet (opens new window)
- Servlet到底是什么(非常透彻) (opens new window)
- Spring Framework Documentation (opens new window)
- Spring Boot Reference Documentation (opens new window)
- Spring Boot → Spring MVC Auto-configuration (opens new window)
- Raw Servlet vs. Spring MVC [closed] (opens new window)
- SpringBoot的Controller层常用注解 (opens new window)
- 从使用传统Web框架到切换到Spring Boot后的总结 (opens new window)
- Spring基础 - SpringMVC 理论说明&请求流程和案例 (opens new window)
- 阿里老司机带你使用Spring框架快速搭建Web工程项目 (opens new window)
- 零基础如何系统学习Java Web? (opens new window)