1.3 Spring Boot与Web应用程序
前面提到Spring家族具备多款开源框架,开发人员可以基于这些开发框架实现各种Spring应用程序。在本节中,我们关注的是基于Spring Boot开发面向Web场景的服务,这也是互联网应用程序最常见的表现形式之一。
1.3.1 剖析一个Spring Web应用程序
在介绍基于Spring Boot的开发模式之前,让我们先将它与传统的Spring MVC进行对比。
1.Spring MVC vs Spring Boot
在典型的Web应用程序中,前后端通常基于HTTP完成请求和响应,开发过程中需要完成HTTP请求的构建、URL地址的映射、对象的序列化和反序列化以及实现各个服务自身内部的业务逻辑,如图1-4所示。
图1-4 HTTP请求和响应过程
我们先来看基于Spring MVC的Web应用程序开发流程,如图1-5所示。
图1-5 基于Spring MVC的Web应用程序开发流程
图1-5包括使用web.xml定义Spring的DispatcherServlet、完成启动Spring MVC的配置文件、编写响应HTTP请求的控制器(Controller),以及部署服务到Web服务器等流程。事实上,基于传统的Spring MVC框架开发Web应用程序逐渐暴露出一些问题,比较典型的就是配置工作过于复杂和繁重,以及缺少必要的应用程序管理和监控机制。
如果想要优化这一套开发流程,有几个点值得我们去挖掘,比方说减少不必要的配置工作、启动依赖项的自动管理、简化部署并提供应用监控等。这些优化点推动了以Spring Boot为代表的新一代开发框架的诞生。基于Spring Boot的Web应用程序开发流程如图1-6所示。
图1-6 基于Spring Boot的Web应用程序开发流程
从图1-6可以看到,它与基于Spring MVC的Web应用程序开发流程在配置信息的管理、服务部署和监控等方面有明显不同。作为Spring家族新的一员,Spring Boot提供了令人兴奋的特性,这些特性的核心价值就是确保了开发过程的简单性,具体体现在编码、配置、部署、监控等多个方面。
● Spring Boot使编码更简单。
我们只需要在Maven中添加一项依赖并实现一个Controller,就可以提供微服务架构中所推崇的RESTful风格接口。
● Spring Boot使配置更简单。
它把Spring中基于XML的功能配置方式转换为Java Config,同时提供了.yml文件来优化原有的基于.properties和.xml文件的配置方案。.yml文件对配置信息的组织更为直观、方便,语义也更为强大。同时,基于自动配置特性,Spring Boot对常见的各种工具和框架均提供了默认的starter组件来简化配置。
● Spring Boot使部署更简单。
在部署方案上,Spring Boot也创造了一键启动的新模式。相较于传统模式下的war包,Spring Boot部署包既包含业务代码和各种第三方类库,同时也内嵌HTTP容器。这种包结构支持java–jar命令方式的一键启动,它不需要部署独立的应用服务器,通过默认的内嵌Tomcat就可以运行整个应用程序。
● Spring Boot使监控更简单。
相较于传统的Spring框架,Spring Boot的一大亮点是引入了内置的监控机制,这是通过Actuator组件来实现的。基于Actuator组件,我们可以查看包含自动配置在内的应用程序的详细信息。另一方面,也可以实时监控应用程序的运行时健康状态。这部分信息中常见的包括内存信息、JVM信息、垃圾回收信息等。例如,可以通过“/env/{name}”端点获取系统环境变量、通过“/mapping”端点获取所有RESTful服务、通过“/dump”端点获取线程工作状态,以及通过“/metrics/{name}”端点获取JVM性能指标等。
2.基于Spring Boot的Web应用程序开发
针对一个基于Spring Boot开发的Web应用程序,其代码组织方式需要遵循一定的项目结构。在本书中,如果不做特殊说明,我们都将使用Maven来管理项目中的结构和包依赖。一个典型的Web应用程序的项目结构包括包依赖、启动类、Controller类以及配置文件等4个组成部分。
● 包依赖。
Spring Boot提供了一系列starter组件来简化各种组件之间的依赖关系。以开发Web应用程序为例,我们需要引入spring-boot-starter-web这个组件,而这个组件中并没有具体的代码,而只包含一些依赖,如下所示:
org.springframework.boot:spring-boot-starter
org.springframework.boot:spring-boot-starter-tomcat
org.springframework.boot:spring-boot-starter-validation
com.fasterxml.jackson.core:jackson-databind
org.springframework:spring-web
org.springframework:spring-webmvc
可以看到,这里包括传统Spring MVC应用程序中会使用到的spring-web和spring-webmvc组件,因此Spring Boot在底层实现上还是基于这两个组件完成对Web请求响应流程的构建的。
在应用程序中引入spring-boot-starter-web组件就像引入一个普通的Maven依赖,如下所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
一旦spring-boot-starter-web组件引入完毕,我们就可以充分利用Spring Boot提供的自动配置机制开发Web应用程序。
● 启动类。
使用Spring Boot的非常重要的一个步骤是创建一个Bootstrap启动类。Bootstrap类结构简单且比较固化,如下所示:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
可以看到,这里引入了一个全新的注解@SpringBootApplication。在Spring Boot中,添加了该注解的类就是整个应用程序的入口,一方面会启动Spring容器,另一方面也会自动扫描代码包结构下的@Component、@Service、@Repository、@Controller等注解,并把这些注解对应的类转化为Bean对象,从而全部加载到Spring容器中。
● Controller类。
Bootstrap类为我们提供了Spring Boot应用程序的入口,相当于应用程序已经具备最基本的骨架。接下来我们就可以添加HTTP请求的访问入口,表现在Spring Boot中就是一系列的Controller类。这里的Controller与Spring MVC中的Controller在概念上是一致的。一个典型的Controller类如下所示:
@RestController
@RequestMapping(value = "accounts")
public class AccountController {
@Autowired
private AccountService accountService;
@GetMapping(value = "/{accountId}")
public Account getAccountById(@PathVariable("accountId") Long accountId) {
Account account = accountService.getAccountById(accountId);
return account;
}
}
请注意,以上代码中包含@RestController、@RequestMapping和@GetMapping这3个注解。其中,@RequestMapping用于指定请求地址的映射关系,@GetMapping的作用等同于指定了GET请求方法的@RequestMapping注解。而@RestController注解是传统Spring MVC中所提供的@Controller注解的升级版,相当于@Controller和@ResponseEntity这两个注解的结合体,会自动使用JSON实现序列化/反序列化操作。
● 配置文件。
注意到在src/main/resources目录下存在一个application.yml文件,这就是Spring Boot中的默认配置文件。例如,我们可以将如下所示的端口、服务名称以及数据库访问等配置信息添加到这个配置文件中:
server:
port: 8081
spring:
application:
name: orderservice
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/appointment
username: root
password: root
事实上,Spring Boot提供了强大的自动配置机制,如果没有特殊的配置需求,开发人员完全可以基于Spring Boot内置的配置体系完成诸如数据库访问相关配置信息的自动集成。
1.3.2 Spring Boot中的技术组件
Spring Boot构建在Spring Framework的基础之上,是新一代的Web应用程序开发框架。我们可以通过图1-7来了解Spring Boot的全貌。
图1-7 Spring Boot整体架构
通过浏览Spring的官方网站,我们可以看到Spring Boot已经成为Spring中最顶级的子项目之一。自2014年4月发布1.0.0版本以来,Spring Boot俨然已经发展为Java EE领域开发Web应用程序的首选框架。
通过前面的描述,可以看到Spring Boot中一个传统Spring框架所不具备的功能特性,就是支持运行时内嵌容器,包含Tomcat、Jetty等支持Servlet规范的多款传统Web容器可供开发人员选择。而在最新的Spring Boot 2.x中,还提供了对Netty以及集成Servlet 3.1+的非阻塞式容器的支持。基于运行时内嵌容器机制,开发人员只需要使用一行java–jar命令就可以启动Web服务了。
另一个通过前面的示例可以看到的功能特性就是自动配置。前面的示例并没有像以前使用Spring MVC一样指定一大堆关于HTTP请求和响应的XML配置。事实上,Spring Boot的运行过程同样还是依赖于Spring MVC,但是它把原本需要开发人员指定的各种配置项设置了默认值并内置在运行时环境中,例如默认的服务器端口就是8080。如果我们对这些配置项没有定制化需求,就可以不做任何的处理,采用既定的开发约定即可。这就是Spring Boot所倡导的约定优于配置(Convention over Configuration)的设计理念。