Java

SpringCloud微服务架构demo

勤劳的小蜜蜂 · 12月6日 · 2019年

项目简介

本文着重于 SpringCloud 架构搭建,Maven 多模块,使用到的 SpringCloud 组件有 Eureka、Zuul、Config、Bus、OpenFeign、Hystrix。

主要业务就是输入院系名称,查询该院系所有的学生信息。

目录结构

demo-springcloud
├── config  // 配置中心
│   ├── basedir     // 本地git
│   ├── pom.xml 
│   └── src
├── eureka  // 注册中心
│   ├── pom.xml
│   └── src
├── gateway // 网关服务
│   ├── pom.xml
│   └── src
├── service // 业务服务
│   ├── pom.xml
│   ├── student-common      // 业务通用模块
│   ├── student-department  // 院系模块
│   └── student-info        // 学生模块
└── pom.xml // 父模块 pom

数据库结构

父模块 pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ye.sp</groupId>
    <artifactId>demo-springcloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka</module>
        <module>gateway</module>
        <module>service</module>
        <module>config</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <properties>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- lombok 工具通过在代码编译时期动态的将注解替换为具体的代码,
        IDEA 需要添加 lombok 插件 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 标识 SpringCloud 的版本 -->
    <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>

    <!-- 配置远程仓库 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

Eureka

Eureka 服务端配置三步走:

  1. 引入依赖
  2. 启动类添加注解
  3. 编写 applicaiotn.yml

1、引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demo-springcloud</artifactId>
        <groupId>com.ye.sp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka</artifactId>

    <!-- eureka server: 提供服务发现与服务注册 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、启动添加注解

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

Eureka 服务端不能使用 @SpringCloud 注解,因为 @SrpingCloud 注解是@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker 三合一

3、编写 application.yml

server:
  port: 7000

spring:
  application:
    name: eureka

eureka:
  client:
    service-url:
      defaultZone: http://${spring.application.name}:${server.port}/eureka/
    register-with-eureka: false   #false表示不向注册中心注册自己。
    fetch-registry: false   #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
  instance:
    hostname: ${spring.application.name}

启动 Eureka 服务,访问 http://localhost:7000/

Gateway

搭建网关服务和 Eureka 类似,也是三步走

  1. 引入依赖
  2. 启动类添加注解
  3. 编写 applicaiotn.yml

1、引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demo-springcloud</artifactId>
        <groupId>com.ye.sp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gateway</artifactId>

    <dependencies>
        <!--
            Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
            Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 服务网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、启动类添加注解

@SpringCloudApplication
@EnableZuulProxy
public class GatewayZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayZuulApplication.class, args);
    }
}

微服务中每个服务都是 Eureka Client端

3、编写 application.yml

server:
  port: 9000

spring:
  application:
    name: zuul

eureka:
  client:
    service-url:
      defaultZone: http://localhost:7000/eureka/

# 暴露所有路由,访问:http://localhost:9000/actuator/routes
management:
  endpoints:
    web:
      exposure:
        include: routes

启动服务,访问 http://localhost:9000/actuator/routes 可以查看所有注册在 Eureka 上的路由

Config、Bus

Config Server 端模块配置几步走(Student 模块配置了 Config Client)

  1. 创建 git 仓库
  2. 引入依赖
  3. 启动类添加注解
  4. 编写 application.yml 文件

1、本文使用的是 gitee 创建了一个私有的仓库,然后上传 application.yml 文件,yml 文件名最好和 spring.application.name 相同,例如 student-info-dev.yml

2、引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>demo-springcloud</artifactId>
        <groupId>com.ye.sp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>config</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bus-amqp -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Cloud Bus可以将分布式系统的节点与轻量级消息代理链接,然后可以实现广播状态更改(例如配置更改)或广播其他管理指令,简单来说就是你在云端 git 修改配置,本地服务收到队列消息就会动态的修改。

Spring Cloud Bus支持RabbitMQ和Kafka,本文我们使用 RabbitMQ。

RabbitMQ 被封装在 spring-cloud-starter-bus-amqp 中,不需要单独引入。

需要先安装 RabbitMQ

3、启动类添加注解

@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
    }
}

4、编写 application.yml

spring:
  application:
    name: config
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/beeij/config-repo.git    # git 仓库地址
          username: username   # git 用户名
          password: password    # git 密码
          basedir: /Users/ye/IdeaProjects/demo-springcloud/config/basedir   # 线上 git 拉取到本地的路径

eureka:
  client:
    service-url:
      defaultZone: http://localhost:7000/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"

如果 Rabbit 是默认配置,此处则不需要配置。

访问 http://localhost:8080/student-info-dev.yml

student-info-dev.yml

Service 模块

Service 模块也是 Maven 多模块项目

通用模块

此模块存放通用的工具类,不同服务间传递的实体,例如本文两个类

StudentInfo.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentInfo {

    private Integer id;

    private String name;

    private String departmentName;

    public static StudentInfo invaild() {
        return new StudentInfo(-1, "", "");
    }
}
DepartmentInfo.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DepartmentInfo {

    private Integer departmentId;

    private String departmentName;

    public static DepartmentInfo vaild() {
        return new DepartmentInfo(-1, "");
    }
}

pom 文件按需引入就可以了

院系模块

正常业务逻辑,需要记得将此服务也注册到 Eureka 上

院系模块只有一个 /department/getid 的 controller,作用是通过输入院系名称来获取院系的 id,此方法主要是用来给学生模块调用的。

学生模块(OpenFeign、Hystrix)

1、引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>service</artifactId>
        <groupId>com.ye.sp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>student-info</artifactId>

    <dependencies>
        <!-- 引入 Web 功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--
            Eureka 客户端, 客户端向 Eureka Server 注册的时候会提供一系列的元数据信息, 例如: 主机, 端口, 健康检查url等
            Eureka Server 接受每个客户端发送的心跳信息, 如果在某个配置的超时时间内未接收到心跳信息, 实例会被从注册列表中移除
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入 Feign, 可以以声明的方式调用微服务 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 引入服务容错 Hystrix 的依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-client</artifactId>
        </dependency>
        <!-- Java Persistence API, ORM 规范 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- MySQL 驱动, 注意, 这个需要与 MySQL 版本对应 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
            <scope>runtime</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-bus-amqp -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

        <dependency>
            <groupId>com.ye.sp</groupId>
            <artifactId>student-common</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

    <!--
        SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
        SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
     -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、配置 bootstrap.yml 文件

spring:
  application:
    name: student-info

  cloud:
    config:
      discovery:
        enabled: true
        service-id: CONFIG
      profile: dev

eureka:
  client:
    service-url:
      defaultZone: http://localhost:7000/eureka/

3、编写启动类

@SpringCloudApplication
@EnableFeignClients
public class StudentInfoApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentInfoApplication.class, args);
    }
}

4、Feign 客户端配置(Feign 服务端不需要配置)

/**
 * student-department:是要调用服务的 spring.application.name
 * fallback = DepartmentClientHystrix.class:是 Hystrix 处理类
 * */

@FeignClient(value = "student-department", fallback = DepartmentClientHystrix.class)
public interface DepartmentClient {

    /**
     * /department/getid:是要调用的 controller
     * method = RequestMethod.GET 调用方法为 get
     * 函数名称自定义
     * */
    @RequestMapping(value = "/department/getid", method = RequestMethod.GET)
    DepartmentInfo getDepartmentInfo(@RequestParam String departmentName);
}

5、Hystrix 熔断降级

当服务不能在对外服务的时候,就会调用 Hystrix 兜底策略

@Component
public class DepartmentClientHystrix implements DepartmentClient{
    @Override
    public DepartmentInfo getDepartmentInfo(String name) {
        return DepartmentInfo.vaild();
    }
}

6、Controller

自动注入 DepartmentClient 类,然后调用方法,实现服务间调用

@RestController
public class StudentInfoController {

    @Autowired
    private StudentService studentService;

    @Autowired
    private DepartmentClient departmentClient;

    @RequestMapping("/get")
    public List<Student> findAllByDepartmentId(@RequestParam Integer departmentId) {
        return studentService.findAllByDepartmentId(departmentId);
    }

    @RequestMapping("/getinfo")
    public List<StudentInfo> getInfo(@RequestParam String departmentName) {
        DepartmentInfo departmentInfo = departmentClient.getDepartmentInfo(departmentName);
        List<Student> studentList = studentService.findAllByDepartmentId(departmentInfo.getDepartmentId());

        List<StudentInfo> studentInfoList = new ArrayList<>();
        for (Student student : studentList) {
            StudentInfo studentInfo = new StudentInfo();
            studentInfo.setDepartmentName(departmentName);
            studentInfo.setId(student.getId());
            studentInfo.setName(student.getName());
            studentInfoList.add(studentInfo);
        }
        return studentInfoList;
    }
}

服务状态

Eureka 注册中心,http://localhost:7000/

网关服务

RabbitMQ 服务

到此微服务架构就搭建完成。

源码下载

评论后可见此区域内容
0 条回应