Springboot+SpringCloud具体使用

目录

创建父项目

配置父项目

整理父项目的目录结构

修改父项目的POM文件 

使用多模块开发项目

创建子项目

配置子项目pom文件

 启动子项目

将子项目放入注册中心

下载consul

启动consul

给父项目中注入依赖

给子项目中注入依赖 

在子项目中写配置文件 

 在子项目的启动类上加注解

使用Feign完成服务之间的通信

导入Feign相关的依赖

使用Feign

创建公共模块

在SpringCloud使用MybatisPlus

 Feign+MyBatisPlus获取数据

​编辑 使用Hystrix实现服务降级

导入Hystrix依赖

配置yml文件

添加@EnableHystrix注解

处理调用的服务的接口

指定fallback的类


创建父项目

当你在创建项目的时候,将打包方式选择了Jar包的方式,那么项目就不会自动导入spring-boot-starter-web依赖,需要自己手动导入。

 选择完之后,点击Next下一步。

创建完父项目后,千万不要急着去创建子项目,不然后面启动项目的时候会出错(需要重启IDEA解决)。 创建完父项目后,要先对父项目整理一下。下面的图片中父项目中已经有了子项目(这是一个错误行为),读者不用去创建子项目,一步一步往下操作即可。

配置父项目

整理父项目的目录结构

 以下是删除过后的目录结构

 

修改父项目的POM文件 

父项目的POM文件中的build标签中的内容可以全部删除

 以下是删除过后的父项目的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.china</groupId>
    <artifactId>test-mall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>test-mall</name>
    <description>test-mall</description>
    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1. 修改父项目中的打包方式

2. 给父项目配置所有的子项目

3. 将父项目中的dependencies标签中的依赖移入dependencyManagement标签中的dependencies标签里(为什么要做这一步:最外面的dependencies标签中的依赖会被所有子模块继承,但是现实情况并不是所有子模块都需要继承父项目中的依赖。)

4. 所有移入dependencyManagement标签中的dependencies标签里的springboot起步依赖都必须要指定版本号(为什么一定要指定版本号: 里面的dependencies标签中的依赖只有当子类在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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.china</groupId>
    <artifactId>test-mall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>  <!--1.父项目的打包方式必须是pom,否则报错-->
    <name>test-mall</name>
    <description>test-mall</description>
    <modules>
        <module>mall-product</module>  <!--2.指定子模块(有哪些子模块,都需要配置进来,目前我就写了一个)-->
    </modules>
    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
    </properties>

    <dependencies>
        <!--这个标签中的依赖会被所有子模块继承(但是现实情况并不是所有子模块都需要继承父项目中的依赖)-->
    </dependencies>

    <dependencyManagement>
        <dependencies><!--这个标签中的依赖只有当子类在POM文件中引入依赖时才会被继承,并且子类引入依赖的时候无需
            指定版本号,由父项目统一指定依赖的版本号,防止出现版本不一致的问题-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <scope>provided</scope>
                <version>${spring-boot.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>${spring-boot.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

使用多模块开发项目

创建子项目

 创建子项目的步骤和上面创建父项目test-mall一致

以下是创建成功后的目录结构

配置子项目pom文件

1. 配置父项目的坐标信息。

2. 导入项目中需要的依赖,不需要指定版本号,因为父项目已经确定版本号,子项目只需要导入即可。

3. 删除bulid标签和dependencyManagement标签,保持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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.china</groupId>
    <artifactId>mall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>mall-product</name>
    <description>mall-product</description>
    <!--配置父项目的坐标信息-->
    <parent>
        <groupId>cn.china</groupId>
        <artifactId>test-mall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <properties>
        <java.version>11</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.6</spring-boot.version>
    </properties>
    <dependencies>
        <!--导入该项目中需要的依赖,不需要写版本号-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

 启动子项目

出现以下界面说明多模块项目创建成功。

将子项目放入注册中心

如果希望注册中心是Nacos的小伙伴,可以阅读另一篇文章SpringCloud+Nacos​​​​​​​

下载consul

 https://developer.hashicorp.com/consul/install  consul下载地址 

启动consul

将下载得到的consul压缩包,解压到本地文件夹,进入consul文件夹,在地址栏使用cmd命令,打开命令行窗口。

输入consul agent -dev然后回车,就可以启动consul了。

在浏览器中输入http://localhost:8500就可以进入consul的可视化界面。

给父项目中注入依赖

在父项目的dependencyManagement标签中的dependencies标签里注入依赖(该依赖的作用是当子项目导入SpringCloud相关的依赖时,不需要指定版本,这个依赖会帮我们下载最合适的版本):

            <!-- 指定 Spring Cloud 版本 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

给子项目中注入依赖 

将子项目注册到consul的注册中心

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

在子项目中写配置文件 

在子项目中的resource文件夹下创建application.yml文件,配置consul的相关信息,application中的name用来指定服务的名字,用于consul区分是否为相同服务,一般用项目的名字作为name值。当需要配置服务集群时,会配置相同name值的服务。

server:
  port: 8081
spring:
  application:
    name: mall-product
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        heartbeat:
          enabled: true 

 在子项目的启动类上加注解

在启动类的上方加@EnableDiscoveryClient注解。

启动子项目后,子项目就会被进入到注册中心中。

使用OpenFeign完成服务之间的通信

每一个子项目就是一个服务,任何一个服务中难免会需要调用另外一个服务的接口,如果服务之间不能相互调用的话,就需要再写一个一模一样的接口,这就会导致代码重复。实现服务之间的通信,就需要用到OpenFeign组件。

导入OpenFeign相关的依赖

导入依赖的时候,哪个服务需要调用另外一个服务的接口,就在那个服务中导入OpenFeign相关的依赖。

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

使用OpenFeign

第一步,我们需要再创建一个子项目给子项目mall-product调用。

在父项目的pom文件中子模块mall-order配置进去

在子模块mall-order中指定父项目的坐标

 第二步,我们需要在这个子项目mall-order中写一个接口供子项目mall-product调用,并且将mall-order注册到consul注册中心中去。

在子模块mall-order中创建了一个controller包,在包里面创建了OrderController类,在里面写了一个最简单的接口,返回结果为String,但是实际情况需要我们返回的是Result类型的结果。这就需要我们去封装一个Result类,用来保存响应的结果。(后面我们会单独创建一个公共的子项目,用来存放实体类、工具类、配置类等一些公共的东西。)

把一个子项目注册到consul注册中心上面已经叙述过了,这里将mall-order注册到consul注册中心的步骤不再阐述。

 第三步,我们需要在子项目mall-product中,写一个接口,用来指定调用的是哪一个服务,以及服务中的哪些接口。

首先在子项目mall-product中创建一个feign包,在里面创建一个OrderFeign接口(命名可以随意,但是一般以Feign结尾用来标识这是一个Feign接口,前缀为调用的服务的名字。)使用@FeignClient注解,注解中使用value属性,用来指定调用的服务的名字。子项目之间的通信是通过Feign根据服务名去consul中拉取服务,然后再由Feign去调用服务中的接口,然后获得响应结果。OrderFeign中的接口需要写全路径名,如果contorller中有前缀,那么就需要在OrderFeign中的接口上使用@RequestMapping注解将前缀也加上。OederFeign中的接口需要与OrderController中的接口一致,包括接口名、参数列表以及返回结果。

第四步,在ProductController中注入OrderFeign,然后调用OrderFeign中的接口。 

在ProductController中使用@Autowired注解,获取OrderFeign接口的对象。在需要调用mall-order 服务中的接口的地方,使用orderFeign对象调用接口即可。

 最后访问localhost:8081/product/hello,就可以看到Hello  World!。 

创建公共模块

创建公共模块,可以将Result类和一些工具类,还有实体类放在里面,当其他模块需要使用工具类和实体类的时候,只需要在pom文件中导入公共模块的坐标就可以使用了。

package cn.util;

/**
 * @author noBody
 * @className: Result
 * @date 2024 09 06
 * @description:
 **/
public class Result {
    private Integer code;
    private String message;
    private Object data;

    public Result() {
    }

    public Result(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }



    public Result(Integer code, String message){
        this.code = code;
        this.message = message;
    }

    public Result(Integer code,Object data){
        this.code = code;
        this.data = data;
    }

    public static Result success(Integer code,Object data){
        return new Result(code,data);
    }

    public static Result success(String message,Object data){
        return new Result(200,message,data);
    }
    public static Result success(String message){
        return new Result(200,message);
    }
    public static Result success(Object data){
        return new Result(200,data);
    }

    public static Result fail(String message , Object data){
        return new Result(404,message,data);
    }

    public static Result fail(Object data){
        return new Result(404,data);
    }

    public static Result fail(String message){
        return new Result(404,message);
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
                '}';
    }
}

复制公共模块的groupId、artifactId、version,粘贴到需要使用公共模块中的类的子项目。使用dependency标签将本地Maven仓库中的项目导入。

在SpringCloud使用MybatisPlus

 SpringBoot使用MybatisPlus 步骤和这篇文章一样。在公共模块中使用CodeGenerator类逆向生成实体类、mapper、service类、controller类。
 

 Feign+MyBatisPlus获取数据

第一步,在OrderController中编写一个接口,获取数据。

第二步,在application.yml中配置datasource和MyBatisPlus信息。(在spring的后面靠边粘贴)

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    hikari:
      connection-timeout: 6000
      maximum-pool-size: 5
  #  jackson:
  #    date-format: yyyy-MM-dd HH:mm:ss
  #    time-zone: GMT+8
  #    serialization:
  #      write-dates-as-timestamps: false

mybatis-plus:
  configuration:
    #开启驼峰功能,数据库字段hello_world 实体类helloWorld 也能对应匹配
    map-underscore-to-camel-case: true
    #结果集自动映射(resultMap)
    auto-mapping-behavior: full
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapping/*Mapper.xml
  global-config:
    # 逻辑删除配置
    db-config:
      # 删除前
      logic-not-delete-value: 1
      # 删除后
      logic-delete-value: 0

 第三步,在启动类上使用@MapperScan注解,指定mapper接口所在的位置。

 使用Hystrix实现服务降级

什么是服务降级:需要调用的是服务A,但是服务A中调用了服务B,服务B中又调用了服务C。突然有一天,服务C中出了bug跑不动了,但是服务A仍然在被访问,但是每当调用服务C的时候就停在那了,然后程序依然在跑,JVM内存就一直不会回收分给这段程序的空间,随着访问量的增加,JVM的内存会一直被占着,这就会极大影响JVM内存容量,会导致JVM内存不足。此时服务降级就会让服务B调用的过程中不再去调用服务C,这样调用完服务B后,就直接返回响应结果,尽管响应的结果是不完整的,但是可以让程序可以成功的跑完,不会占用JVM内存。Hystrix就可以很好的去判断任何一个服务是否可以正常的运行,不可以正常运行的就会去做服务降级。

导入Hystrix依赖

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>2.2.10.RELEASE</version>
</dependency>

配置yml文件

feign:
  client:
    # 配置
    config:
      #default为全局配置,如需对指定服务记录日志,换成服务名即可
      default:
        loggerLevel: FULL
  hystrix:
    enabled: true
  circuitbreaker:
    enabled: true

添加@EnableHystrix注解

在启动类的上方添加@EnableHystrix注解,开启服务降级。

处理调用的服务的接口

创建一个类实现OrderFeign中的所有接口,对其中的所有接口进行处理,当接口出现异常时,做出一些提示信息或者返回一些特定数据。并且要使用@Component注解将这个类加入IOC容器,交给Spring管理。

@Component
public class OrderHystrix implements OrderFeign {
    @Override
    public String hello() {
        return "服务器异常,请稍后重试!";
    }

    @Override
    public Result queryAll() {
        return Result.fail("服务器异常,请稍后重试!");
    }
}

指定fallback的类

在OrderFeign接口上方的@FeignClient注解中fallback里面指定Class类型的类。

可以自行测试,当关闭order服务后,当调用order中的接口时,会返回OrderHystrix类中的对应的接口的提示信息,实现服务降级。 

使用gateway提供统一的请求入口

想要在项目中使用gateway,我们可以创建一个子模块,专门用来配置gateway,并且需要将这个子模块,加入注册中心交给SpringCloud管理。

第一步,创建一个mall-gateway的子模块,将他交给父项目管理,并且要进注册中心

第二步,导入gateway的依赖 ,pom文件中不能有spring-boot-web-starter依赖,因为gateway依赖中自带webflux依赖,如果两个都有会冲突

       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

第三步,配置application.yml文件,设置路由、断言、过滤器(gateway是cloud的子级,与consul同级)

    gateway:
      routes:
        - id: provider-web #服务id,根据需要随意起名
          uri: lb://web # lb://服务名 服务名是spring.application.name值
          predicates:
            - Path=/web/**  #当gateway接收以web开头的请求后会将请求转发给http://localhost:8082
          filters:
            - StripPrefix=1 #去除前缀 原始请求路径:/web/subpath 去除后将请求拼接成

这里我们需要配置两个路由,分别为mall-product和mall-order服务,需要做的就是将原本web的地方换成对应的服务名,这样gateway就可以去注册中心找和服务名对应的url进行字符串拼接,就可以做到请求转发了。uri中的lb:是负载均衡的意思,lb是loadbalance的缩写,添加了lb:就说明使用负载均衡。

什么是负载均衡:负载均衡可以提高我们服务的可用性,让我们的服务更稳定。那为什么可以提高呢,是因为我们可以写多个除了端口号不一样外一模一样的服务(这样的多个服务,也叫做服务集群),当有一天某一个服务坏了,另一个服务可以顶上,而不是服务直接没办法用了。

    

路由中的断言predicates和过滤器filters,读者可以自行前往官网阅读。SpringCloud-gateway 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值