欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第2章 构建单个微服务

程序员文章站 2022-03-10 17:01:26
在深入接触微服务之前,首先得知道怎么创建单个微服务工程。2.1 使用Spring Boot构建第一个微服务Spring Boot的设计目标是用来简化新Spring应用的初始搭建以及开发过程。它是建立在Spring标准上的一个抽象层,使用特定的方式进行配置,从而使开发人员不再需要定义样板化的配置。Spring Boot的简单是相对于以前的SpringFramework入门容易,但是要完全掌握,用好Spring Boot,我们还有很长的路要走。下面通过一个简单的例子,我们通过官网提供的网页创建...

目录

# 2.1 使用Spring Boot构建第一个微服务

2.1.1 工程结构

2.1.2 Spring Boot基础

2.1.3 Spring Boot Starters

2.1.4 RESTful

2.1.5 EndPoint

2.2 小结


在深入接触微服务之前,首先得知道怎么创建单个微服务工程。

2.1 使用Spring Boot构建第一个微服务

Spring Boot的设计目标是用来简化新Spring应用的初始搭建以及开发过程。它是建立在Spring标准上的一个抽象层,使用特定的方式进行配置,从而使开发人员不再需要定义样板化的配置。

Spring Boot的简单是相对于以前的Spring Framework入门容易,但是要完全掌握,用好Spring Boot,我们还有很长的路要走。

下面通过一个简单的例子,我们通过官网提供的网页创建一个可以运行的Spring Boot基础工程。

2.1.1 工程结构

打开链接https://start.spring.io/,按照下图2.1填写信息,生成我们的第一个微服务工程。

第2章 构建单个微服务
​​​​​​图2.1 Spring工程包生成

 

点击Generate Project按钮,将生成的zip包解压并导入Intellj Idea中。可以看到如图2.2所示的结构。

第2章 构建单个微服务
图2.2 Spring Boot项目结构

 

可以看到这是一个标准的Maven工程。Spring为我们自动生成了几个文件及目录:

  • CustomerApplication.java文件是customer这个项目的启动类。在Spring Boot项目中,不需要将项目发布到Tomcat之类的Web容器中,直接以application的方式运行启动类即可使用内置的Web容器正常启动项目,并对外提供服务。
  • application.properties文件是项目使用的配置文件,Spring Boot中摒弃了以前Spring的繁琐配置,改为使用更多的约定以及更简单的配置来进行。

新建的工程中这个文件是空的,强烈建议为每个Spring Boot工程配置spring.application.name来指明当前服务的实例名。Customer工程中设置为spring.application.name=customer。

resources下的static和templates是Spring Boot默认的放置网页及静态元素的地方,这个后面用到的时候再讨论。

打开CustomerApplication.java文件,我们可以看到一个简单的main方法。代码如下所示:

package cn.com.hanbinit.customer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 使用Spring Boot构建的项目都应该添加这个注解,它可以告诉框架,这个类是项目的引导类
public class CustomerApplication {
    public static void main(String[] args) {
        SpringApplication.run(CustomerApplication.class, args); // 启动服务
    }
}

这里我们只需要知道这个类是Spring
Boot的启动类即可。注解@SpringBootApplication标识这个类是工程的启动类。

pom.xml文件中引入了web 服务的starter包,如下代码:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

spring-boot-starter-web包含了spring-web和spring-webmvc包,这些可以通过IDE查看。为CustomerApplication类添加注解@RestController,并添加下面的方法提供一个对外的接口/hello,代码如下所示:

@RequestMapping(name = "/hello", method = RequestMethod.GET) // 定义一个URI是/hello的GET请求
public String hello(){
    return "hello";
}

打开浏览器访问http://localhost:8080/hello, 可以看到图2.3的结果。

第2章 构建单个微服务
图2.3 浏览器访问hello接口

 

至此,我们第一个通过Spring Boot创建的对外服务就已经可以使用了。

2.1.2 Spring Boot基础

在上一节,我们通过编写很少的代码就实现了一个对外的接口,并且测试可以访问。回忆以前使用Spring
MVC的时候是如何实现上面这样一个接口的呢?步骤如下:

(1)配置web.xml。
(2)配置加载配置文件。
(3)配置日志文件。
(4)最后写完代码放在tomcat中启动。

作者还记得前几年网上充斥了大量的“如何整合SSH框架”、“如何整合SSM框架”之类的文章,还记得当时遇到好些初学者搭建完框架后,就不想再进一步学习了。

技术架构上的“解耦”从某种程度上来说一直在推动代码和框架越来越简单化。微服务概念的提出,将“解耦”这个说法更具体化了。我们将一个大的项目拆分成若干个微服务,单个微服务只处理某一种业务,各个微服务从根本上分开,达到“解藕”的作用。

注意:微服务的拆分并不是一定按照业务来的,但是一般都是按照业务来进行拆分的。

Spring Boot的详细资料在官网都可以查到,本节只会以较少的篇幅讲述一些后面需要用到的基础。重新回到上节的代码,再看下完整的CustomerApplication.java文件内容:

package cn.com.hanbinit.customer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class CustomerApplication {

@RequestMapping(name = "/hello", method = RequestMethod.GET)
    public String hello(){
        return "hello";
    }

    public static void main(String[] args) {
        SpringApplication.run(CustomerApplication.class, args);
    }
}

对上面的代码进行分析:

  • @RestController 注解相当于将\@Controller和\@ResponseBody一起使用。它属于类级别的注解,它告诉框架这个类定义了一组基于REST的服务,并且所有服务的请求和响应都会被默认序列化和反序列化成JSON。它会让视图解析器失效,不能跳转页面视图,这个注解基本都用在纯接口类上。也是我们在使用Spring
    Boot编写代码时最常用的接口之一。

  • @RequestMapping指定了接口请求的上下文路径以及请求方式等内容。它可以用在类级别和方法级别。用在类上,就表示对这个类中的所有接口设置了URI前缀,用在方法上,对应的就是当前接口真实的URI。
  • @SpringBootApplication这个注解几乎用在每个Spring Boot项目的启动类上。

查看@SpringBootApplication注解的源码可以看到如下代码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

可以看到它其实就是@SpringBootConfiguration、@EnableAutoConfiguration以及@ComponentScan的结合体。

@SpringBootConfiguration来源于@Configuration,和我们以前用Spring Framework时配置的@Configuration注解一样,将当前类中使用@Bean标记的方法注入到容器中管理。

@EnableAutoConfiguration 主要作用是扫描 ClassPath下所有的 META-INF/spring.factories 配置文件,并将其中的 EnableAutoConfiguration 对应的配置项通过反射机制实例化为对应标注了 @Configuration 的形式的配置类,然后交给Spring管理。

@ComponentScan是我们很熟悉的一个注解,和以前的xml配置项<context:component-scan>很像。用来标记需要扫描类以便交给Spring管理的类路径。

Spring Boot提供了一种方便的方式去启动程序,就是我们在上面看到的main方法,在大多数情况下,我们都不需要去修改这个main方法。

在配置文件application.properties中,我们可以添加一些Spring
Boot程序定义好的配置项,以此来快速实现某些功能。常用的几个配置项如下:

  • 制定项目名称:spring.application.name。
  • 日志相关配置:logger.**。
  • 端口号配置:server.port。
  • 数据库相关配置:spring.datasource.**。

上面这几类只是最基本的,但是刚才我们的程序一行配置文件都没有写,那么程序是怎么启动的呢?8080这个端口号是在哪里配置的?

大部分的配置项都有默认值,比如8080这个端口号,配置项对应的是server.port,默认值就是8080。如果在application.properties文件中添加下面的配置项:

server.port=8001

重新启动应用,会发现原来的8080端口已经不能正常访问,取而代之的8001端口访问正常,图2.4中显示的是使用8001端口访问时/hello接口的返回。

第2章 构建单个微服务
图2.4 通过端口8001访问接口

 

前面的接口并没有传输任何参数,那么在这里要怎么传参呢?

一般情况下,我们的传参分下面三种情况:

http://localhost:8001/hello?name=xxx GET  

http://localhost:8001/hello/xxx GET  

http://localhost:8001/hello POST
{
“name” : “xxxx”
}

第一种情况是我们常用的情况,我们为了说明上面三种情况,建立新的接口类,添加三个对外接口,代码如下:

package cn.com.hanbinit.customer.controller;

import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.*;

@RestController
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello0(@RequestParam String name){
        return "hello " + name;
    }

    @RequestMapping(value = "/hello/{name}", method = RequestMethod.GET)
    public String hello1(@PathVariable String name){
        return "hello " + name;
    }

    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String hello2(@RequestBody Customer customer){
        return "hello " + customer.getName();
    }
}

class Customer{
    private String name;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

上面代码中定义的三个接口分别对应了前面提到的三种传参形式。接下来,分别看一下:

第一个方法hello0定义的接口访问方式如图2.5,这种情况适合需要传递一些简单但是项目比较多的参数时使用。这种形式会指明每个参数的名称,可以比较清晰的表示出我们想要传递的参数。但是要注意的是,这种情况的参数值不能带有一些特定的符号,如&,&等。

第2章 构建单个微服务
图2.5 hello?name=xxx格式的访问

 

hello定义的接口访问方式如图2.6所示,这种情况是这几年比较流行的写法,在代码中指定了URL中某个部分的特殊定义,在传参的时候需要按照最初的设定传递,同上面的接口一样,GET请求都不能带有特殊符号。

第2章 构建单个微服务
图2.6 hello/xxx格式的访问

 

最后一种方式是通过非URL传参的方式来实现的,这种情况一般用在非GET,DELETE类型的请求中,他可以传递一些相对复杂的参数,并且可以按照既定的格式来传递,由上面的代码可以看到,body中传递的其实是一个实体类。

这种情况在平时的接口定义中,使用的比较多,一些复杂的查询接口也需要通过这种参数来进行参数传递。具体的调用方式参见图2.7所示。

第2章 构建单个微服务
图2.7 通过body传递Json格式参数的实例

 

2.1.3 Spring Boot Starters

Spring Boot原生提供了很多开箱即用的starter依赖,这些依赖将以前传统的Spring开发过程中一些需要的jar进行了整合,使我们在业务开发时能够通过一个starter引入某种类型的配置,同时,在整合的过程中,做了一些内部的约定,可以让我们在进行业务开发的过程中,少关注一些框架的配置,多关注业务本身。

可以将这一系列的starter依赖理解为可插拔的插件,按需使用。每个starter都包含了许多的依赖项,这些依赖项可简化我们的配置,我们在一般使用的时候可以不用关注starter本身的依赖。比如说:我们需要使用Spring的JPA来操作数据库,我们只需要引入spring-boot-starter-data-jpa就可以了。

Spring官方的Starter命名方式为spring-boot-starter-*。在这里,我们只单独拿出来一个starter说下,所有的Starter大家都可以在官方提供的文档中找到:

https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#using-boot-starter

这里不做过多的说明,后面用到的时候会详细说明。

2.1.4 RESTful

RESTful是一种针对web服务的结构设计风格,REST独立于底层协议,是一种对外表现的设计约束。一般满足REST设计原则的我们就称之为RESTful 接口。在REST中,每一个对象都是通过URL来表示的,通过method给出的动作构成一个完整的操作。

REST接口很重要的一点是无状态性。客户端和服务器之间的交互是无状态的。从客户端到服务器的每个请求都必须包含请求所必需的信息。如果服务器在请求之间的任何时间出现任何意外事故,客户端不需要获得通知,客户端下次的请求仍旧应该获得同样正确的结果。

此外,无状态请求可以由任何可用服务器来接收并处理,这十分适合云计算之类的环境。客户端还可以本地缓存数据以改进性能。

Microsoft Azure官方推出的最佳实践中有一篇讲述API设计的文章,其中提到了Leonard Richardson对Web API设计的四个等级。

  • Level 0: 定义一个URI,所有操作都是对该URI的POST请求。
  • Level 1: 创建单独的个人资源的URI。
  • Level 2: 使用HTTP方法来定义操作资源。
  • Level 3: 使用超媒体 (HATEOAS, described below)。

目前大部分的API设计还停留在Level 2。Spring Boot
在2.0版本后推出了WebFlux,这个在后面我们会有专门的介绍。

2.1.5 EndPoint

Endpoint在国内大多数时候都被翻译为“端点”,本书也使用这个翻译来描述。
继续使用这节我们创建的项目向pom.xml中添加spring-boot-starter-actuator依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

然后重新启动服务。可以看到Customer这个服务中已经可以访问一些Spring
Boot内置的端点。这些端点包括很多类型,一般可以分为控制类和监控类。端点虽然看起来都是一些很小的接口,但是在Spring
Boot的使用过程中,端点的使用频率要比想象的高很多。

在本书使用的版本中,只默认开启了info和health两个信息查看端点。其他端点的开启需要手工配置。

2.2 小结

本节我们使用Spring Boot构建了一个可以对外提供接口的工程,并且对工程的结构做了简单说明。在这个基础上,我们对开发过程中常见的接口传参过程也做了简单讨论。最后通过对RESTful和EndPoint的讨论,让我们对API有了进一步的认识。

本节的内容是本系列最为基础的,在本节很多东西都只是提到但并未展开讲,后续的内容中会按需展开。

本文地址:https://blog.csdn.net/weixin_50209853/article/details/112000052