• SpringCloud


    一、介绍

     

    Cloud各种组件的停更/升级/替换

     
    以前:
    在这里插入图片描述
     

    现在:
    在这里插入图片描述

    二、微服务框架构建

    约定 > 配置 > 编码

    (一) IDEA新建project工作空间

    1、微服务cloud整体聚合父工程Project

    (1)New Project

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    (2)字符编码

    在这里插入图片描述

    (3)注解生效激活

    在这里插入图片描述

    (4)java编译版本

    在这里插入图片描述

    (5)File Type 过滤

    在这里插入图片描述

     

    2、父工程POM

    
    
    <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.0modelVersion>
    
      <groupId>com.xxxx.springcloudgroupId>
      <artifactId>SpringCloudStudyartifactId>
      <version>1.0-SNAPSHOTversion>
      <packaging>pompackaging>
    
      <name>Mavenname>
      
      <url>http://maven.apache.org/url>
      <inceptionYear>2001inceptionYear>
    
      <distributionManagement>
        <site>
          <id>websiteid>
          <url>scp://webhost.company.com/www/websiteurl>
        site>
      distributionManagement>
    
      
      <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <maven.compiler.source>1.8maven.compiler.source>
        <maven.compiler.target>1.8maven.compiler.target>
        <junit.version>4.12junit.version>
        <log4j.version>1.2.17log4j.version>
        <lombok.version>1.16.18lombok.version>
        <mysql.version>5.1.47mysql.version>
        <druid.version>1.1.16druid.version>
        <mybatis.spring.boot.version>1.3.0mybatis.spring.boot.version>
      properties>
      
      
      <dependencyManagement>
        <dependencies>
          
          <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-dependenciesartifactId>
            <version>2.2.2.RELEASEversion>
            <type>pomtype>
            <scope>importscope>
          dependency>
          
          <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-dependenciesartifactId>
            <version>Hoxton.SR1version>
            <type>pomtype>
            <scope>importscope>
          dependency>
          
          <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-alibaba-dependenciesartifactId>
            <version>2.1.0.RELEASEversion>
            <type>pomtype>
            <scope>importscope>
          dependency>
          <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>${mysql.version}version>
          dependency>
          <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>${druid.version}version>
          dependency>
          <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>${mybatis.spring.boot.version}version>
          dependency>
          <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>${junit.version}version>
          dependency>
          <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>${lombok.version}version>
            <optional>trueoptional>
          dependency>
        dependencies>
      dependencyManagement>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
            <configuration>
              <fork>truefork>
              <addResources>trueaddResources>
            configuration>
          plugin>
        plugins>
      build>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

     

    3、Maven工程落地细节

    Maven 中的 DependencyManagement 和 Dependencies

    dependencyManagement:

    Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。

    使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。

    Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement 元素的项目,然后它就会使用这个dependencyManagement 元素中指定的版本号。

    在这里插入图片描述
    这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version就可。

    • dependencyManagement 里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖

    • 如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom

    • 如果子项目中指定了版本号,那么会使用子项目中指定的jar版本

    maven中跳过单元测试

    在这里插入图片描述

    4、Run Dashboard

    没有Run Dashboard,可以在工程目录下找.idea文件夹下的workspace.xml,在其中增加如下组件

      <component name="RunDashboard">
        <option name="configurationTypes">
          <set>
            <option value="SpringBootApplicationConfigurationType" />
          set>
        option>
      component>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (二) Rest微服务工程构建

    1、支付模块8001

    cloud-provider-payment8001 微服务提供者支付Module模块

    在这里插入图片描述

    在这里插入图片描述

    项目结构:

    在这里插入图片描述

    (1)pom.xml

    
    <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>SpringCloudStudyartifactId>
            <groupId>com.xxxx.springcloudgroupId>
            <version>1.0-SNAPSHOTversion>
        parent>
        <modelVersion>4.0.0modelVersion>
    
        <artifactId>cloud-provider-payment8001artifactId>
    
        <properties>
            <maven.compiler.source>8maven.compiler.source>
            <maven.compiler.target>8maven.compiler.target>
        properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
            <dependency>
                <groupId>org.mybatis.spring.bootgroupId>
                <artifactId>mybatis-spring-boot-starterartifactId>
            dependency>
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>druid-spring-boot-starterartifactId>
                <version>1.1.10version>
            dependency>
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-jdbcartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
        dependencies>
        
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    (2)application.yml

    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包 com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: com.xxxx.springcloud.entities    # 所有Entity别名类所在包
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    (3)主启动

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (4)创建数据库和数据表

    在这里插入图片描述

    -- ----------------------------
    -- Table structure for payment
    -- ----------------------------
    DROP TABLE IF EXISTS `payment`;
    CREATE TABLE `payment`  (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
      `serial` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
    
    -- ----------------------------
    -- Records of payment
    -- ----------------------------
    INSERT INTO `payment` VALUES (1, '123');
    INSERT INTO `payment` VALUES (2, '234');
    INSERT INTO `payment` VALUES (3, '345');
    
    SET FOREIGN_KEY_CHECKS = 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    (5)实体类

    主实体 Payment

    package com.xxxx.springcloud.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Payment {
        private Long id;
        private String serial;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Json封装体CommonResult

    这个类是传递给前端的,前端不管什么 payment,它只要响应状态码、message…

    package com.xxxx.springcloud.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CommonResult<T> {
        private Integer code;
        private String message;
        private T data;
    
        public CommonResult(Integer code, String message) {
            this(code, message, null);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    (6)dao

    package com.xxxx.springcloud.dao;
    
    import com.xxxx.springcloud.entities.Payment;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    @Mapper
    public interface PaymentDao {
    
        /**
         * 创建一个 payment
         *
         * @param payment
         * @return
         */
        public int create(Payment payment);
    
        /**
         * 根据 id 查询 payment
         *
         * @param id
         * @return
         */
        public Payment getPaymentById(@Param("id") Long id);
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    mapper文件

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.xxxx.springcloud.dao.PaymentDao">
    
        <resultMap id="BaseResultMap" type="com.xxxx.springcloud.entities.Payment">
            <id column="id" property="id" jdbcType="BIGINT"/>
            <result column="serial" property="serial" jdbcType="VARCHAR"/>
        resultMap>
    
        <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
            insert into payment(serial)
            values (#{serial})
        insert>
    
        <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
            select id, serial
            from payment
            where id = #{id}
        select>
    
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    (7)service

    PaymentService

    package com.xxxx.springcloud.service;
    
    import com.xxxx.springcloud.entities.CommonResult;
    import com.xxxx.springcloud.entities.Payment;
    
    public interface PaymentService {
    
        /**
         * 创建一个 payment
         * @param payment
         * @return
         */
        CommonResult create(Payment payment);
    
        /**
         * 根据 id 查询 payment
         * @param id
         * @return
         */
        CommonResult getPaymentById(Long id);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    PaymentServiceImpl

    package com.xxxx.springcloud.service.impl;
    
    import com.xxxx.springcloud.dao.PaymentDao;
    import com.xxxx.springcloud.entities.Payment;
    import com.xxxx.springcloud.service.PaymentService;
    import org.apache.ibatis.annotations.Param;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class PaymentServiceImpl implements PaymentService {
    
        @Resource
        private PaymentDao paymentDao;
    
    
        public int create(Payment payment){
            return paymentDao.create(payment);
        }
        public Payment getPaymentById(Long id){
            return paymentDao.getPaymentById(id);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    (8)controller

    package com.xxxx.springcloud.controller;
    
    import com.xxxx.springcloud.entities.CommonResult;
    import com.xxxx.springcloud.entities.Payment;
    import com.xxxx.springcloud.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    
    @RestController
    @Slf4j
    @RequestMapping("/payment")
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
        @PostMapping("/create")
        public CommonResult create(Payment payment) {
            return paymentService.create(payment);
        }
    
        @GetMapping("/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id){
            return paymentService.getPaymentById(id);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    (9)测试

    Chrom浏览器可能不支持Post请求,可以使用PostMan工具测试。

    在这里插入图片描述

    在这里插入图片描述
     

    总结:

    1.建Module
    2.改pom
    3.写yml
    4.主启动
    5.业务类

    2、热部署

    (1)Adding devtools to your project

            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (2)Adding plugin to your pom.xml

    我们在父工程中添加。

      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
            <configuration>
              <fork>truefork>
              <addResources>trueaddResources>
            configuration>
          plugin>
        plugins>
      build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (3)Enabling automatic build
    在这里插入图片描述

    (4)Update the value of

    快捷键:ctrl+shift+alt+/

    在这里插入图片描述
    在这里插入图片描述

    (5)重启IDEA

    注意:开发阶段开启热部署,生产阶段必须关闭

     

    3、订单模块80

    cloud-consumer-order80 微服务消费者订单Module模块

    (1)改pom

    
    <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>SpringCloudStudyartifactId>
            <groupId>com.xxxx.springcloudgroupId>
            <version>1.0-SNAPSHOTversion>
        parent>
        <modelVersion>4.0.0modelVersion>
    
        <artifactId>cloud-consumer-order80artifactId>
    
        <properties>
            <maven.compiler.source>8maven.compiler.source>
            <maven.compiler.target>8maven.compiler.target>
        properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
        dependencies>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    (2)写yml

    server:
      port: 80
    
    • 1
    • 2

    (3)主启动

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    (4)entities
    主实体 Payment

    package com.xxxx.springcloud.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Payment {
        private Long id;
        private String serial;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Json封装体CommonResult

    这个类是传递给前端的,前端不管什么 payment,它只要响应状态码、message…

    package com.xxxx.springcloud.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class CommonResult<T> {
        private Integer code;
        private String message;
        private T data;
    
        public CommonResult(Integer code, String message) {
            this(code, message, null);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    (5)首说RestTemplate
    是什么:

    RestTemplate提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集

    官网地址:

    https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

    使用:

    使用restTemplate访问restful接口非常的简单粗暴无脑

    url:REST请求地址
    requestMap:请求参数
    ResponseBean.class:HTTP响应转换被转换成的对象类型

    (6)config配置类

    package com.xxxx.springcloud.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class ApplicationConfig {
    
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    (7)controller

    package com.xxxx.springcloud.controller;
    
    import com.xxxx.springcloud.entities.CommonResult;
    import com.xxxx.springcloud.entities.Payment;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.Resource;
    
    @RestController
    @Slf4j
    public class OrderController {
    
        public static final String PaymentSrv_URL = "http://localhost:8001";
    
        @Resource
        private RestTemplate restTemplate;
    
        /**
         * 客户端用浏览器是get请求,但是底层实质发送post调用服务端8001
         *
         * @param payment
         * @return
         */
        @GetMapping("/consumer/payment/create")
        public CommonResult<Payment> create(Payment payment) {
            return restTemplate.postForObject(PaymentSrv_URL + "/payment/create", payment, CommonResult.class);
        }
    
        @GetMapping("/consumer/payment/get/{id}")
        public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
            return restTemplate.getForObject(PaymentSrv_URL + "/payment/get/" + id,CommonResult.class,id);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    注意:/payment/get/路径中 get 后面的/不要忘了加,否则会一直报错。

    在这里插入图片描述

    在这里插入图片描述

    (8)测试

    客户端用浏览器是get请求,但是底层实质发送post调用服务端8001
    在这里插入图片描述
    但是数据库中只有主键并没有数据

    在这里插入图片描述

    8001中的 create 不要忘记@RequestBody注解

        //只传给前端CommonResult,不需要前端了解其他的组件
        @PostMapping(value = "/payment/create")
        public CommonResult create(@RequestBody Payment payment){
            int result = paymentService.create(payment);
            log.info("*****插入结果:"+result);
            if(result > 0){
                return new CommonResult(200,"插入数据成功",result);
            }else{
                return new CommonResult(444,"插入数据失败",null);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    数据插入成功
    在这里插入图片描述

     

    4、工程重构

    项目中存在相同的代码(entities包下的Payment.class和CommonResult.class),造成代码冗余,可以进行重构。
    通过Maven聚合父工程,把相同重复的代码移到公开公用的工程里面,还可以放第三方接口、工具类,统一调配使用。

    (1)建立公共Module
    在这里插入图片描述

    (2)改pom

    
    <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>cloud2020artifactId>
            <groupId>com.xxxx.springcloudgroupId>
            <version>1.0-SNAPSHOTversion>
        parent>
        <modelVersion>4.0.0modelVersion>
    
        <artifactId>cloud-api-commonsartifactId>
    
        <properties>
            <maven.compiler.source>8maven.compiler.source>
            <maven.compiler.target>8maven.compiler.target>
        properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>cn.hutoolgroupId>
                <artifactId>hutool-allartifactId>
                <version>5.1.0version>
            dependency>
        dependencies>
    
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    (3)将entities包复制到cloud-api-commons
    在这里插入图片描述

    (4)使用Maven打包发布上传到公用本地库里

    打开Maven窗口,执行clean测试一下,无误后出现BUILD SUCCESS,然后执行install

    在这里插入图片描述

    (5)删除重复entities,引入maven install的jar包坐标即可使用

            
            <dependency>
                <groupId>com.xxxx.springcloudgroupId>
                <artifactId>cloud-api-commonsartifactId>
                <version>1.0-SNAPSHOTversion>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

     

    三、Eureka 服务注册与发现

     

    (一) Eureka基础知识

     

    1、什么是服务治理?

    Springcloud 封装了Netflix 公司开发的Eureka模块来实现服务治理。

    在传统的 rpc 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。‘’

     

    2、什么是服务注册?

    Eureka采用了CS的设计架构,Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。

    在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址)。

    下左图是Eureka系统架构,右图是Dubbo的架构,请对比:

    在这里插入图片描述
     

    3、Eureka 两组件

    Eureka包含两个组件:Eureka ServerEureka Client

    • Eureka Server 提供服务注册服务
      各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

    • EurekaClient 通过注册中心进行访问
      是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。

     

    (二) 单机Eureka构建步骤

     

    eurekaServer端cloud-eureka-server7001

    服务注册中心

    1、创建module

    cloud-eureka-server7001

    2、pom.xml

    
    <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>SpringCloudStudyartifactId>
            <groupId>com.xxxx.springcloudgroupId>
            <version>1.0-SNAPSHOTversion>
        parent>
        <modelVersion>4.0.0modelVersion>
    
        <artifactId>cloud-eureka-server7001artifactId>
    
        <properties>
            <maven.compiler.source>8maven.compiler.source>
            <maven.compiler.target>8maven.compiler.target>
        properties>
    
        <dependencies>
    
            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
            dependency>
    
            
            <dependency>
                <groupId>com.xxxx.springcloudgroupId>
                <artifactId>cloud-api-commonsartifactId>
                <version>${project.version}version>
            dependency>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-actuatorartifactId>
            dependency>
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
            dependency>
        dependencies>
    
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    1.X和2.X的对比说明:

    以前的老版本(当前使用2018)
    <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-eurekaartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    现在新版本(当前使用2020.2)
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、application.yml

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: localhost #eureka服务端的实例名称
      client:
        #false表示不向注册中心注册自己。
        register-with-eureka: false
        #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4、主启动类

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7001.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这是个服务注册中心,主要干的活就是服务注册,不需要写业务类。
    但是注意:Eureka有两个组件,一定要标清楚哪个是Server,哪个是Client。@EnableEurekaServer代表服务注册中心。

    5、测试

    在这里插入图片描述

    出现上面图标,表示Eureka 服务端安装成功。No instances available表示当前没有服务注册进来,红色警告是Eureka的自我保护机制

    EurekaClient端cloud-provider-payment8001

    将注册进EurekaServer成为服务提供者provider

    1、在pom.xml将 Eureka-client 依赖引入

            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、在application.yml添加Eureka相关配置

    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:7001/eureka
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、主启动类使用注解@EnableEurekaClient标注这是个Eureka Client端

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、测试

    注意: 要先启动EurekaServer

    在这里插入图片描述

    这样就注册进来了,入住进Eureka服务器的名称就是8001yml中配置的spring.application.name。

    EurekaClient端cloud-consumer-order80

    将注册进EurekaServer成为服务消费者consumer

    1、pom.xml

            
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2、application.yml

    server:
      port: 80
    
    spring:
      application:
        name: cloud-order-service
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true。
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetchRegistry: true
        service-url:
          defaultZone: http://localhost:7001/eureka
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3、主启动类

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、测试

    先要启动EurekaServer——7001服务,再要启动服务提供者provider——8001服务

    在这里插入图片描述
    cloud-order-server服务已入住,查询功能也可以正常执行

     

    (三) 集群Eureka构建步骤

     

    Eureka集群原理说明

    在这里插入图片描述
    问题:微服务RPC远程服务调用最核心的是什么?

    高可用,试想你的注册中心只有一个only one, 它出故障了那就呵呵( ̄▽ ̄)"了,会导致整个为服务环境不可用,所以解决办法:搭建Eureka注册中心集群 ,实现负载均衡+故障容错

    eurekaServer端cloud-eureka-server7002

    1、参考cloud-eureka-server7001,新建cloud-eureka-server7002

    2、改pom

    3、修改映射配置

    找到C:\Windows\System32\drivers\etc路径下的hosts文件,修改映射配置添加进hosts文件
    在这里插入图片描述

    4、改yml

    以前单机版

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: localhost #eureka服务端的实例名称
      client:
        #false表示不向注册中心注册自己。
        register-with-eureka: false
        #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7001:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com #eureka服务端的实例名称
      client:
        #false表示不向注册中心注册自己。
        register-with-eureka: false
        #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://eureka7002.com:7002/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7002:

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com #eureka服务端的实例名称
      client:
        #false表示不向注册中心注册自己。
        register-with-eureka: false
        #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://eureka7001.com:7001/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5、主启动

    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7001.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    cloud-provider-payment8001发布到Eureka集群

    application.yml

    # 集群版
    defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  
    
    • 1
    • 2
    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包 com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: com.xxxx.springcloud.entities    # 所有Entity别名类所在包
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          #defaultZone: http://localhost:7001/eureka
          # 集群版
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    cloud-consumer-order80发布到Eureka集群

    application.yml

    # 集群版
    defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka  
    
    • 1
    • 2
    server:
      port: 80
    
    spring:
      application:
        name: cloud-order-service
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true。
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetchRegistry: true
        service-url:
          # defaultZone: http://localhost:7001/eureka
          # 集群版
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    测试

    在这里插入图片描述

    在这里插入图片描述

    支付服务提供者集群环境构建

    参考cloud-provider-payment8001,新建cloud-provider-payment8002

    修改8001和8002的controller,默认的负载均衡方式是轮询,看执行查询具体调用那台provider

    package com.xxxx.springcloud.controller;
    
    import com.xxxx.springcloud.entities.CommonResult;
    import com.xxxx.springcloud.entities.Payment;
    import com.xxxx.springcloud.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    
    @RestController
    @Slf4j
    //@RequestMapping("/payment")
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
    
    
    
        @Value("${server.port}")
        private String serverPort;
    
    
    
        //只传给前端CommonResult,不需要前端了解其他的组件
        @PostMapping(value = "/payment/create")
        public CommonResult create(@RequestBody Payment payment){
            int result = paymentService.create(payment);
            log.info("*****插入结果:"+result);
            if(result > 0){
                return new CommonResult(200,"插入数据成功,serverPort:"+serverPort,result);
            }else{
                return new CommonResult(444,"插入数据失败",null);
            }
        }
        @GetMapping(value = "/payment/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id){
            Payment payment = paymentService.getPaymentById(id);
            log.info("*****插入结果:"+payment);
            if(payment != null){
                return new CommonResult(200,"查询成功,serverPort:"+serverPort,payment);
            }else{
                return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    测试:
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    8001和8002也都访问正常,那如果我们用80访问呢?发现怎么刷新都是8001,这是因为我们的源程序地址是写死的:

    在这里插入图片描述

    单机版写死是没有问题的,但是现在有8001、8002了,所有不应该再关注具体的IP和端口,而是只认服务名称。代码修改一下再试。

    在这里插入图片描述

    在这里插入图片描述

    发现报错了,现在对外暴露的不再是地址和端口,只认微服务名称了,可是微服务并不知道下面有几个,找不到这个主机名称,需要使用@LoadBalanced注解开启RestTemplate负载均衡功能。
    提前说一下:这个就是后面要介绍的Ribbon负载均衡功能。

    在这里插入图片描述

    然后测试,多次刷新,就会发现8001、8002端口交替出现。

    在这里插入图片描述
    这样Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号,且该服务还有负载均衡功能了。O(∩_∩)O

    在这里插入图片描述

     

    (四) actuator微服务信息完善

     

    1、主机名称:服务名称修改

    当前问题:含有主机名称

    在这里插入图片描述

    修改8001:application.xml

      instance:
        instance-id: payment8001
    
    • 1
    • 2
    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包 com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: com.xxxx.springcloud.entities    # 所有Entity别名类所在包
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          #defaultZone: http://localhost:7001/eureka
          # 集群版
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      instance:
        instance-id: payment8001
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    8002同理

    测试:
    在这里插入图片描述

    2、访问信息有IP信息提示

    当前问题:没有ip提示

    在这里插入图片描述

    修改8001:application.yml

    prefer-ip-address: true     #访问路径可以显示IP地址
    
    • 1
    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包 com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: com.xxxx.springcloud.entities    # 所有Entity别名类所在包
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          #defaultZone: http://localhost:7001/eureka
          # 集群版
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      instance:
        instance-id: payment8001
        prefer-ip-address: true     #访问路径可以显示IP地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    8002同理

    测试:
    在这里插入图片描述

     

    (五) 服务发现Discovery

     
    对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息

    1、修改8001的controller

    加上如下代码

        @Resource
        private DiscoveryClient discoveryClient;
    
        @GetMapping(value = "/payment/discovery")
        public Object discovery(){
            List<String> services = discoveryClient.getServices();//得到所有的微服务
            for (String element : services){
                log.info("*****element:"+element);
            }
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");//得到一个具体微服务的所有实例
            for (ServiceInstance instance : instances){
                log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
            }
            return this.discoveryClient;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    完整代码:

    package com.xxxx.springcloud.controller;
    
    import com.xxxx.springcloud.entities.CommonResult;
    import com.xxxx.springcloud.entities.Payment;
    import com.xxxx.springcloud.service.PaymentService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @RestController
    @Slf4j
    //@RequestMapping("/payment")
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
    
    
    
        @Value("${server.port}")
        private String serverPort;
    
    
    
    
    
    
    
        @Resource
        private DiscoveryClient discoveryClient;
    
        @GetMapping(value = "/payment/discovery")
        public Object discovery(){
            List<String> services = discoveryClient.getServices();//得到所有的微服务
            for (String element : services){
                log.info("*****element:"+element);
            }
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");//得到一个具体微服务的所有实例
            for (ServiceInstance instance : instances){
                log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
            }
            return this.discoveryClient;
        }
    
    
    
    
    
    
    
        //只传给前端CommonResult,不需要前端了解其他的组件
        @PostMapping(value = "/payment/create")
        public CommonResult create(@RequestBody Payment payment){
            int result = paymentService.create(payment);
            log.info("*****插入结果:"+result);
            if(result > 0){
                return new CommonResult(200,"插入数据成功,serverPort:"+serverPort,result);
            }else{
                return new CommonResult(444,"插入数据失败",null);
            }
        }
        @GetMapping(value = "/payment/get/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id){
            Payment payment = paymentService.getPaymentById(id);
            log.info("*****插入结果:"+payment);
            if(payment != null){
                return new CommonResult(200,"查询成功,serverPort:"+serverPort,payment);
            }else{
                return new CommonResult(444,"没有对应记录,查询ID:"+id,null);
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    2、主启动类

    @EnableDiscoveryClient//服务发现
    
    • 1
    package com.xxxx.springcloud;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    @EnableDiscoveryClient//服务发现
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    8002同理

    3、测试

    在这里插入图片描述
    在这里插入图片描述

     

    (六) Eureka自我保护

     

    1、故障现象

    概述:保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。

    如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式

    在这里插入图片描述

    2、导致原因

    为什么会产生Eureka自我保护机制?

    为了防止可以正常运行的EurekaClient,但是与 EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除

    什么是自我保护模式?

    默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。

    在这里插入图片描述
    在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。

    它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着

    综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

    一句话:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存

    属于CAP里面的AP分支

    3、禁止自我保护

    现在可以不用集群版了,只用开一个,在 application.yml 中把集群配置改为单机版

    (1)注册中心eureakeServer端7001

    出厂默认,自我保护机制是开启的 eureka.server.enable-self-preservation=true,使用eureka.server.enable-self-preservation = false 可以禁用自我保护模式

    application.yml:

      server:
        #关闭自我保护机制,保证不可用服务被及时踢除
        enable-self-preservation: false
        # 默认时间是90s,改为2s
        eviction-interval-timer-in-ms: 2000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com #eureka服务端的实例名称
      client:
        #false表示不向注册中心注册自己。
        register-with-eureka: false
        #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
          defaultZone: http://eureka7001.com:7001/eureka/
      server:
        #关闭自我保护机制,保证不可用服务被及时踢除
        enable-self-preservation: false
        # 默认时间是90s,改为2s
        eviction-interval-timer-in-ms: 2000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    关闭效果:
    在这里插入图片描述

    (2)生产者客户端eureakeClient端8001

    默认配置:

    eureka.instance.lease-renewal-interval-in-seconds=30 #单位为秒(默认是30秒)
    eureka.instance.lease-expiration-duration-in-seconds=90 #单位为秒(默认是90秒)
    
    • 1
    • 2

    配置:

    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    lease-expiration-duration-in-seconds: 2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包 com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    mybatis:
      mapperLocations: classpath:mapper/*.xml
      type-aliases-package: com.xxxx.springcloud.entities    # 所有Entity别名类所在包
    
    eureka:
      client:
        #表示是否将自己注册进EurekaServer默认为true
        register-with-eureka: true
        #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:7001/eureka
          # 集群版
          #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      instance:
        instance-id: payment8001
        prefer-ip-address: true     #访问路径可以显示IP地址
        #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
        lease-renewal-interval-in-seconds: 1
        #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
        lease-expiration-duration-in-seconds: 2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    测试:

    7001和8001都配置完成,先启动7001再启动8001

    http://eureka7001.com:7001/

    在这里插入图片描述

    模拟8001出现了故障关闭了,以前7001还会保留,但是现在:
    在这里插入图片描述

  • 相关阅读:
    精准营销!用机器学习完成客户分群!
    【Bug】Unable to make field private final int java.time.LocalDate.year accessible
    基于最小二乘支持向量机(LS-SVM)进行分类、函数估计、时间序列预测和无监督学习(Matlab代码实现)
    Matlab:奇异值
    web网页设计期末课程大作业:美食餐饮文化主题网站设计——美食汇5页HTML+CSS+JavaScript
    设计模式之【桥接模式】
    JavaWeb Session会话
    Leetcode 289. Game of Life
    贪心算法介绍
    JavaScript系列之解构赋值
  • 原文地址:https://blog.csdn.net/lln1540295459/article/details/126006991