SpringBoot项目拆分为SpringCloud微服务 - 从0-1开始搭建微服务

6,888 阅读8分钟

前言

距离我搭建完个人开发框架并写完笔记也已经过去很长时间了,在这段时间内我学习了SpringCloud相关的知识,从这篇笔记开始把之前搭建的单体框架拆分成微服务框架,并希望在从中学到更多的知识,以及更多维度上的考虑;在此搭建的过程中,也希望各位大佬多多指点,多提建议,共同进步。

参考:

确定SpringCloud基础项目结构

关于微服务框架中都有什么服务模块,因为现在没什么业务场景,我就暂时按着学习到的服务模块来确定基础项目结构了。

  • ywh-cloud-core 主要业务代码
  • ywh-cloud-gateway 服务网关
  • ywh-cloud-auth 服务认证模块
  • ywh-cloud-common 服务公共模块
  • ywh-cloud-eureka 服务注册中心

网关服务我暂时使用的是Zuul来实现网关的,后续有可能改成SpringCloudGateway这个组件,毕竟是官方自己出的,用起来应该更如丝滑般柔顺吧。

最终的项目结构

关于如何在IDEA中创建多模块请参考我 springboot版本创建多模块项目,这里唯一的区别在于:在单体的SpringBoot多模块项目中,每个模块是有依赖关系的,最终只有一个启动类。

而在SpringCloud的多模块中,除了common模块,其他模块都有单独的启动类,并且没有依赖关系,每个微服务都是通过注册中心来发现对方,具体创建方式可以看我上方贴出来的方志朋老师的教程,或者我的SpringCloud练习实战。

创建完的项目结构如下图所示

最终目录结构

创建完成后需要对一些文件进行修改

  • 所有模块中pom.xml文件需要继承最外层的父pom.xml文件,默认创建后< parent >标签中是spring-boot-starter-parent,并且删除< relativePath/ >标签,否则mvn clean时会报错说找不到父pom文件
<!-- 父pom -->
<parent>
    <groupId>com.ywh</groupId>
    <artifactId>springcloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</parent>

<!-- 以下依赖除了common模块,都引入 -->

<!-- 引入web依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- springboot的测试类 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  • 最外层的pom.xml文件添加以下内容
<!-- 父pom.xml中的必须为pom类型 -->
<packaging>pom</packaging>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
    <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>

<dependencyManagement>
    <!--dependencyManagement在多模块项目中统一管理依赖版本问题-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 子模块 -->
<modules>
    <module>ywh-cloud-core</module>     <!-- 主要写代码服务 -->
    <module>ywh-cloud-eureka</module>   <!-- eureka注册中心 -->
    <module>ywh-cloud-common</module>   <!-- 微服务的基础服务模块 -->
    <module>ywh-cloud-gateway</module>  <!-- 微服务的网关服务 -->
    <module>ywh-cloud-auth</module>     <!-- 微服务的权限认证服务 -->
</modules>

最外层的pom.xml文件最好不要放任何依赖,只需要作为一个管理版本的功能就可以了。

  • Greenwich.SR2这个是官方提供SpringBoot2.1.x版本的对应SpringCloud的版本,正式的版本其实是Greenwich.RELEASE

为什么用SR2而不用RELEASE版本是因为后面我想要集成OAuth2正式版本中有一个依赖拉不下来,所以换成了SR2版本

官方查看boot对应cloud版本 页面滑到下面就能看到了

  • 在所有的启动类上配置扫描路径
@SpringBootApplication(scanBasePackages = "com.ywh")

服务之间的注册和发现Eureka

SpringCloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、 分布式会话等等。它运行环境简单,可以在开发人员的电脑上跑;另外说明SpringCloud是基于SpringBoot的,所以需要开发中对SpringBoot有一定的了解, 另外对于“微服务架构” 不了解的话,可以通过搜索引擎搜索“微服务架构”了解下。

图解什么是微服务

启动EurekaServer注册中心

  • ywh-cloud-eureka服务中引入spring-cloud-starter-netflix-eureka-server依赖
<!-- eurekaServer注册中心依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  • 启动一个服务注册中心,只需要一个注解@EnableEurekaServer,这个注解需要在SpringBoot工程的启动类上加,表明自己是注册中心服务
@SpringBootApplication(scanBasePackages = "com.ywh")
@EnableEurekaServer
public class CloudEurekaApplication {

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

}
  • eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成),在默认情况下erureka server 也是一个eureka client ,必须要指定一个 server;ywh-cloud-eureka的配置文件appication.yml:
# 端口号
server:
  port: 8761
# 配置注册服务中心
eureka:
  instance:
    hostname: localhost
  # 配置关闭自我保护,并按需配置Eureka Server清理无效节点的时间间隔。生产环境不建议关闭
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 6000
    peer-node-read-timeout-ms: 90000
    response-cache-update-interval-ms: 5000
  client:
    # 表明自己不是一个客户端,并且不进行自注册
    register-with-eureka: false
    fetch-registry: false
    # 注册中心的访问地址
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# 配置应用程序名称
spring:
  application:
    name: cloud-eureka

启动EurekaClient客户端

当client向server注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka server 从每个client实例接收心跳消息。 如果心跳超时, 则通常将该实例从注册server中删除。

  • 在所有有启动类的模块中引入spring-cloud-starter-netflix-eureka-client依赖
<!-- eureka客户端依赖 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 通过注解@EnableEurekaClient 表明自己是一个eurekaclient,实际上在Edgware版本之后,不再需要添加该注解,不过写上也没有关系,同样这个注解添加到启动类上即可。

  • 还需要在配置文件中注明自己的服务注册中心的地址,application.yml配置文件如下,只展示一个yml文件,其他文件只是应用程序名称和端口号不一样就可以了。

# 端口号
server:
  port: 9001
# 配置应用程序名称
spring:
  application:
    name: cloud-core

# eureka配置 客户端配置,注册到服务中心
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

把所有项目都启动后,以后启动项目的时候网关服务最好最后一个启动,打开网址 http://localhost:8761 可查看注册的实例。

eureka注册中心

服务之间如何互相调用接口我暂时不在这里贴了,有兴趣的可以先行Google或者参考我的SpringCloud自我练习实战

平移一些可用的类

因为是在我自己的单体框架的基础上开始构建的微服务,有一些我已经在SpringBoot2.1版本的个人应用开发框架中写过了,这里就直接把可以用的一些类都放到微服务下来,就不再一一介绍怎么集成的过程了。

  • Druid和MybatisPlus放到ywh-cloud-core服务中,具体集成过程参考以前的笔记集成Druid + MybatisPlus

  • 返回前端的json格式封装类Result,放到ywh-cloud-common基础服务中,具体代码Result

暂时没有把基础的controll、service等放进来是因为需要MybatisPlus的依赖,如果把MybatisPlus放到common模块下,那么所有的微服务都需要配置jdbc了,所以在没想好之前先不动这个了

以上这些因为我都已经实现一次了所以在这个笔记中不再记载,就直接都平移过来了。

引入网关Zuul

在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、断路器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统,一个简单的微服务系统如下图(图片是引用方志朋老师的):

A服务和B服务是可以相互调用的,作图的时候忘记了,并且配置服务也是注册到服务注册中心的

在Spring Cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、Ngnix),再到达服务网关(zuul集群),然后再到具体的服。 服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改配置。

Zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如/api/user转发到到user服务,/api/shop转发到到shop服务。zuul默认和Ribbon结合实现了负载均衡的功能。

使用网关的好处

  • zuul学习笔记

  • 后端暴露接口往往都是动态调整的,使用网关代理转发,简化前端调用的难度,可以不用考虑每个微服务的host,port以及负载和动态调整,只要知道调用的是哪个微服务即可。

  • 使用网关后可以不直接暴露接口给外部,强化了后端微服务的安全性。并且可以进行token验证。

  • 网关可以进行服务聚合,将一些通用请求聚合在一起,减少请求次数。

  • 可以配合shiro、security等进行一系列权限校验工作。

开始

  • ywh-cloud-gateway模块服务的 pom 文件中引入 spring-cloud-starter-netflix-zuul 依赖。
<!-- 路由网关zuul的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 在其入口applicaton类加上注解@EnableZuulProxy,开启zuul的功能
@SpringBootApplication
@EnableZuulProxy
public class CloudGatewayApplication {

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

}
  • 配置文件application.yml
# zuul configuration
zuul:
  routes:
    api-a:
      path: /cloud-core/**
      serviceId: cloud-core
    api-b:
      path: /cloud-auth/**
      serviceId: cloud-auth

ywh-cloud-core模块中写一个测试接口,此模块的端口为9001,但是我们通过网关的端口9003来访问接口,如果能访问到就证明网关已经起了作用了,当我们高可用部署ywh-cloud-core时Zuul网关会替我们负载均衡的来访问接口。

@GetMapping("test1")
public Result test1(){
    return Result.successJson("成功了!!");
}

我只是实现了网关最简单的应用,更多的使用方法还是需要更深入的学习才可以结合具体的业务实现最好的方式。

笔记到此已经初步搭建好了一个基础的微服务框架,后面继续在这个框架上完善。