19. SpringCloud学习笔记

笔记整理来源 B站UP主狂神说:https://www.bilibili.com/video/BV1jJ411S7xr
文档来源:https://www.kuangstudy.com/bbs/1374942542566551554

1. 学习前言

1.1 学习前提

* 熟练使用SpringBoot 微服务快速开发框架
* 了解过Dubbo + Zookeeper 分布式基础
* 电脑配置内存不低于8G(我自己的是16G)
  • 给大家看下多个服务跑起来后的内存开销图:
    在这里插入图片描述

1.2 文章大纲

Spring Cloud 五大组件

* 服务注册与发现——Netflix Eureka
*  负载均衡:

      * 客户端负载均衡——Netflix Ribbon
    * 服务端负载均衡:——Feign(其也是依赖于Ribbon,只是将调用方式RestTemplete 更改成Service 接口)
*  断路器——Netflix Hystrix
*  服务网关——Netflix Zuul
*  分布式配置——Spring Cloud Config

1.3 常见面试题

1.1 什么是微服务?

1.2 微服务之间是如何独立通讯的?

1.3 SpringCloudDubbo有那些区别?

1.4 SpringBootSpringCloud,请谈谈你对他们的理解

1.5 什么是服务熔断?什么是服务降级?

1.6 微服务的优缺点分别是什么?说下你在项目开发中遇到的坑

1.7 你所知道的微服务技术栈有哪些?列举一二

1.8 EurekaZookeeper都可以提供服务注册与发现的功能,请说说两者的区别

2. 微服务概述

2.1 什么是微服务?

什么是微服务?

微服务(Microservice Architecture) 是近几年流行的一种架构思想,关于它的概念很难一言以蔽之。

究竟什么是微服务呢?我们在此引用ThoughtWorks 公司的首席科学家 Martin Fowler 于2014年提出的一段话:

原文:https://martinfowler.com/articles/microservices.html

汉化:https://www.cnblogs.com/liuning8023/p/4493156.html

  • 就目前而言,对于微服务,业界并没有一个统一的,标准的定义。
  • 但通常而言,微服务架构是一种架构模式,或者说是一种架构风格,它体长将单一的应用程序划分成一组小的服务,每个服务运行在其独立的自己的进程内,服务之间互相协调,互相配置,为用户提供最终价值,服务之间采用轻量级的通信机制(HTTP)互相沟通,每个服务都围绕着具体的业务进行构建,并且能狗被独立的部署到生产环境中,另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应该根据业务上下文,选择合适的语言,工具(Maven)对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。

再来从技术维度角度理解下:

  • 微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。

2.2 微服务与微服务架构

微服务

强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,狭义的看,可以看作是IDEA中的一个个微服务工程,或者Moudel。IDEA 工具里面使用Maven开发的一个个独立的小Moudel,它具体是使用SpringBoot开发的一个小模块,专业的事情交给专业的模块来做,一个模块就做着一件事情。强调的是一个个的个体,每个个体完成一个具体的任务或者功能。

微服务架构

一种新的架构形式,Martin Fowler 于2014年提出。

微服务架构是一种架构模式,它体长将单一应用程序划分成一组小的服务,服务之间相互协调,互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务之间采用轻量级的通信机制 (如HTTP)互相协作,每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境中,另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具(如Maven)**对其进行构建。

2.3 微服务优缺点

优点

  • 单一职责原则;
  • 每个服务足够内聚,足够小,代码容易理解,这样能聚焦一个指定的业务功能或业务需求;
  • 开发简单,开发效率高,一个服务可能就是专一的只干一件事;
  • 微服务能够被小团队单独开发,这个团队只需2-5个开发人员组成;
  • 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的;
  • 微服务能使用不同的语言开发;
  • 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins,Hudson,bamboo;
  • 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果,无需通过合作才能体现价值;
  • 微服务允许利用和融合最新技术;
  • 微服务只是业务逻辑的代码,不会和HTML,CSS,或其他的界面混合;
  • 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库

缺点

  • 开发人员要处理分布式系统的复杂性;
  • 多服务运维难度,随着服务的增加,运维的压力也在增大;
  • 系统部署依赖问题;
  • 服务间通信成本问题;
  • 数据一致性问题;
  • 系统集成测试问题;
  • 性能和监控问题;

2.4 微服务技术栈有那些?

| **微服务技术条目**          | 落地技术                                             |
| -------------------- | ------------------------------------------------ |
| 服务开发                 | SpringBootSpringSpringMVC|
| 服务配置与管理              | Netfix公司的Archaius、阿里的Diamond|
| 服务注册与发现              | EurekaConsulZookeeper|
| 服务调用                 | Rest、PRC、gRPC                                    |
| 服务熔断器                | HystrixEnvoy|
| 负载均衡                 | RibbonNginx|
| 服务接口调用(客户端调用服务的简化工具) | Fegin|
| 消息队列                 | KafkaRabbitMQActiveMQ|
| 服务配置中心管理             | SpringCloudConfigChef|
| 服务路由(API网关)          | Zuul|
| 服务监控                 | ZabbixNagiosMetricsSpecatator|
| 全链路追踪                | ZipkinBraveDapper|
| 数据流操作开发包             | SpringCloud Stream(封装与RedisRabbitKafka等发送接收消息) |
| 时间消息总栈               | SpringCloud Bus                                  |
| 服务部署                 | DockerOpenStackKubernetes|

2.5 为什么选择SpringCloud作为微服务架构

  1. 选型依据
  • 整体解决方案和框架成熟度
  • 社区热度
  • 可维护性
  • 学习曲线
  1. 当前各大IT公司用的微服务架构有那些?
  • 阿里:dubbo+HFS
  • 京东:JFS
  • 新浪:Motan
  • 当当网:DubboX
  1. 各微服务框架对比
| 功能点/服务框架 | Netflix/SpringCloud | Motan | gRPC | Thri t | Dubbo/DubboX |
| —————— | ———————————————————————————— | —————————————————- | ————————— | ———— | —————————— |
| 功能定位 | 完整的微服务框架 | RPC框架,但整合了ZK或Consul,实现集群环境的基本服务注册发现 | RPC框架 | RPC框架 | 服务框架 |
| 支持Rest | 是,Ribbon支持多种可拔插的序列号选择 |||||
| 支持RPC ||(Hession2) ||||
| 支持多语言 |(Rest形式) |||||
| 负载均衡 |(服务端zuul+客户端Ribbon),zuul-服务,动态路由,云端负载均衡Eureka(针对中间层服务器) |(客户端) |||(客户端) |
| 配置服务 | Netfix ArchaiusSpring Cloud Config Server 集中配置 |(Zookeeper提供) ||||
| 服务调用链监控 |(zuul),zuul提供边缘服务,API网关 |||||
| 高可用/容错 |(服务端Hystrix+客户端Ribbon) |(客户端) |||(客户端) |
| 典型应用案例 | Netflix | Sina | Google | Facebook | |
| 社区活跃程度 || 一般 || 一般 | 2017年后重新开始维护,之前中断了5|
| 学习难度 | 中等 |||||
| 文档丰富程度 || 一般 | 一般 | 一般 ||
| 其他 | Spring Cloud Bus为我们的应用程序带来了更多管理端点 | 支持降级 | Netflix内部在开发集成gRPC | IDL定义 | 实践的公司比较多 |

3. SpringCloud入门概述

3.1 SpringCloud是什么?

Spring官网:https://spring.io/
在这里插入图片描述
在这里插入图片描述

3.2 SpringCloud和SpringBoot的关系

  • SpringBoot专注于开苏方便的开发单个个体微服务;
  • SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务,整合并管理起来,为各个微服务之间提供:配置管理、服务发现、断路器、路由、为代理、事件总栈、全局锁、决策竞选、分布式会话等等集成服务;
  • SpringBoot可以离开SpringCloud独立使用,开发项目,但SpringCloud离不开SpringBoot,属于依赖关系;
  • SpringBoot专注于快速、方便的开发单个个体微服务,SpringCloud关注全局的服务治理框架;

3.3 Dubbo 和 SpringCloud技术选型

  1. 分布式+服务治理Dubbo: 目前成熟的互联网架构,应用服务化拆分 + 消息中间件
  2. Dubbo 和 SpringCloud对比可以看一下社区活跃度:
    https://github.com/dubbo
    https://github.com/spring-cloud
    对比结果:
|        | Dubbo         | SpringCloud                  |
| ------ | ------------- | ---------------------------- |
| 服务注册中心 | Zookeeper     | Spring Cloud Netfilx Eureka  |
| 服务调用方式 | RPC           | REST API                     |
| 服务监控   | Dubbo-monitor | Spring Boot Admin            |
| 断路器    | 不完善           | Spring Cloud Netfilx Hystrix |
| 服务网关   || Spring Cloud Netfilx Zuul    |
| 分布式配置  || Spring Cloud Config          |
| 服务跟踪   || Spring Cloud Sleuth          |
| 消息总栈   || Spring Cloud Bus             |
| 数据流    || Spring Cloud Stream          |
| 批量任务   || Spring Cloud Task            |

最大区别:Spring Cloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式
严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这个优点在当下强调快速演化的微服务环境下,显得更加合适。
社区支持与更新力度的区别
总结:二者解决的问题域不一样:Dubbo的定位是一款RPC框架,而SpringCloud的目标是微服务架构下的一站式解决方案。

3.4 SpringCloud能干嘛?

Distributed/versioned configuration 分布式/版本控制配置
Service registration and discovery 服务注册与发现
Routing 路由
Service-to-service calls 服务到服务的调用
Load balancing 负载均衡配置
Circuit Breakers 断路器
Distributed messaging 分布式消息管理
…

3.5 SpringCloud下载

官网:http://projects.spring.io/spring-cloud/

版本号有点特别:
在这里插入图片描述
SpringCloud没有采用数字编号的方式命名版本号,而是采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如最早的Realse版本:Angel,第二个Realse版本:Brixton,然后是Camden、Dalston、Edgware,目前最新的是Hoxton SR4 CURRENT GA通用稳定版。

自学参考书:
SpringCloud Netflix 中文文档:https://springcloud.cc/spring-cloud-netflix.html
SpringCloud 中文API文档(官方文档翻译版):https://springcloud.cc/spring-cloud-dalston.html
SpringCloud中国社区:http://springcloud.cn/
SpringCloud中文网:https://springcloud.cc
SpringCloud项目:https://spring.io/projects/spring-cloud

4. SpringCloud Rest学习环境搭建:服务提供者

4.1 介绍

  • 我们会使用一个Dept部门模块做一个微服务通用案例Consumer消费者(Client)通过REST调用Provider提供者(Server)提供的服务。
  • 回顾Spring,SpringMVC,Mybatis等以往学习的知识。
  • Maven的分包分模块架构复习。
一个简单的Maven模块结构是这样的:
-- app-parent: 一个父项目(app-parent)聚合了很多子项目(app-util\app-dao\app-web...)
  |-- pom.xml
  |
  |-- app-core
  ||---- pom.xml
  |
  |-- app-web
  ||---- pom.xml
  ......

一个父工程带着多个Moudule子模块

MicroServiceCloud父工程(Project)下初次带着3个子模块(Module)

  • microservicecloud-api 【封装的整体entity/接口/公共配置等】
  • microservicecloud-consumer-dept-80 【服务提供者】
  • microservicecloud-provider-dept-8001 【服务消费者】

4.2 SpringCloud版本选择

| SpringBoot | SpringCloud       | 关系                                 |
| ---------- | ----------------- | ---------------------------------- |
| 1.2.x      | Angel版本(天使)       | 兼容SpringBoot1.2x                   |
| 1.3.x      | Brixton版本(布里克斯顿)  | 兼容SpringBoot1.3x,也兼容SpringBoot1.4x |
| 1.4.x      | Camden版本(卡姆登)     | 兼容SpringBoot1.4x,也兼容SpringBoot1.5x |
| 1.5.x      | Dalston版本(多尔斯顿)   | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 1.5.x      | Edgware版本(埃奇韦尔)   | 兼容SpringBoot1.5x,不兼容SpringBoot2.0x |
| 2.0.x      | Finchley版本(芬奇利)   | 兼容SpringBoot2.0x,不兼容SpringBoot1.5x |
| 2.1.x      | Greenwich版本(格林威治) |                                    |

实际开发版本关系:使用后两个

| spring-boot-starter-parent |          | spring-cloud-dependencles |          |
|:--------------------------:| --------:|:-------------------------:|:--------:|
|          **版本号**           | **发布日期** |          **版本号**          | **发布日期** |
|       1.5.2.RELEASE        |  2017-03 |        Dalston.RC1        |  2017-x  |
|       1.5.9.RELEASE        |  2017-11 |      Edgware.RELEASE      | 2017-11  |
|       1.5.16.RELEASE       |  2018-04 |        Edgware.SR5        | 2018-10  |
|       1.5.20.RELEASE       |  2018-09 |        Edgware.SR5        | 2018-10  |
|       2.0.2.RELEASE        |  2018-05 |  Fomchiey.BULD-SNAPSHOT   |  2018-x  |
|       2.0.6.RELEASE        |  2018-10 |       Fomchiey-SR2        | 2018-10  |
|       2.1.4.RELEASE        |  2019-04 |       Greenwich.SR1       | 2019-03  |

4.3 创建项目

1. 创建空项目

创建一个空的项目,选择路径和输入名称
在这里插入图片描述

2. 创建父项目

右键项目->new module
在这里插入图片描述
新建model
在这里插入图片描述
项目路径
在这里插入图片描述
pom配置
https://spring.io/projects/spring-cloud

<?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.xxx</groupId>
    <artifactId>springcloud_parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--继承springboot的父标签-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
    </parent>

    <!--自定义properties属性-->
    <properties>
        <spring.cloud-version>Hoxton.SR6</spring.cloud-version>
    </properties>
    <!--维护版本-->
    <dependencyManagement>
        <dependencies>
            <!--维护spring-cloud版本-->
            <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>
</project>

4.4 链接数据库创建创建实例

  • 新建父工程项目springcloud,切记Packageing是pom模式
  • 主要是定义POM文件,将后续各个子模块公用的jar包等统一提取出来,类似一个抽象父类
  1. 选择maven项目点击下一步
    在这里插入图片描述
  2. 选择创建的路径,及名称,点击完成
    在这里插入图片描述
  3. 删除src
    在这里插入图片描述
  4. 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.xxx</groupId>
    <artifactId>1_springCloud</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!--为下面依赖包版本设置参数-->
        <junit.version>4.12 </junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>
    <!--打包方式-->
    <packaging>pom</packaging>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>0.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springCloud的依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.3</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--数据库-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.28</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.8</version>
            </dependency>
            <!--SpringBoot 启动器-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.2.2</version>
            </dependency>
            <!--日志测试~-->
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.11</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

4.4.1 springcloud-api 项目公共实体

  1. new module
    在这里插入图片描述
  2. 选择maven,下一步
    在这里插入图片描述
  3. springcloud-api ,点击完成
    在这里插入图片描述
  4. 引入当前springcloud-api 的pom依赖
    <!--当前的Module自己需要的依赖,如果父依赖中已经配置版本,这里不需要写依赖版本-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
  1. 新建数据库和表
-- 创建数据库
drop database if exists db01;
create database db01 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

-- 创建表
CREATE TABLE `dept` (
  `deptno` bigint(20) NOT NULL AUTO_INCREMENT,
  `dname` varchar(60) DEFAULT NULL,
  `db_source` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='部门表'

-- 添加数据
INSERT INTO dept(dname,db_source) VALUES ('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('项目部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('研发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('运维部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES ('人事部',DATABASE());

  1. springcloud-api 实体类结构图
    在这里插入图片描述
    路径:src/main/java/com/xxx/springcloud/pojo/Dept.java
    代码:
package com.xxx.springcloud.pojo;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@Data
@NoArgsConstructor
@Accessors(chain = true)//开启链式写法 普通写法:new Dept().setid(1);   链式写法:new Dept().setid(1).setname("test")....

/*实体类实现序列化*/
public class Dept implements Serializable { //数据库的表和当前实体类映射,类表关系映射
    private Long deptno;//主键
    private String dname;
    //存在于哪个数据库的字段 ~ 微服务,一个服务对应一个数据库,同一个信息可能存在于不同的数据库
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }
}

4.4.2 springcloud-provider-dept-8001 创建服务的提供者maven项目

  1. 右键父类项目,new->module…
    在这里插入图片描述
  2. 选择maven,下一步
    在这里插入图片描述
  3. 输入名称 springcloud-provider-dept-8001,点击完成
    在这里插入图片描述
  4. pom.xml引入依赖
 <!--服务提供者8001端口 maven项目-->
    <artifactId>springcloud-provider-dept-8001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--要拿到实体类,要配置api  module 导入自己写的module springcloud-api-->
        <dependency>
            <groupId>com.xxx</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--Junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <!--Mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--数据库数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <!--日志测试-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <!--SpringBoot启动器-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--SpringBoot web启动-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--jetty 类似于tomcat 在此无实际作用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <!--热部署工具-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>
  1. 配置8001提供者的application.yml
    路径:src/main/resources/application.yml
server:
  port: 8001

#mybatis配置
mybatis:
  type-aliases-package: com.lemon.springcloud.pojo
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/mybatis-config.xml

#spring的配置
spring:
  application:
    name: springcloud-provider-dept
    #数据源的配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource #数据源为druid
    driver-class-name: com.mysql.jdbc.Driver #数据库驱动
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&servetTimeZone=Asia/Shanghai
    username: root
    password: root


  1. 创建mybaits配置对应的文件夹,及文件如下图
    在这里插入图片描述
  2. 配置mybaits config-location对应的配置文件
    路径:src/main/resources/mybatis/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 全局参数 -->
    <settings>
        <!-- 使全局的映射器启用或禁用缓存  开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

</configuration>

  1. 创建Dao接口类
    路径:src/main/java/com/xxx/springcloud/dao/DeptDao.java
package com.xxx.springcloud.dao;

import com.xxx.springcloud.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
public interface DeptDao {
    //添加一个部门
    public boolean addDept(Dept dept);

    //根据id查出一个部门
    public Dept queryById(Long id);

    //查询所有部门信息
    public List<Dept> queryAll();

}

  1. 创建Mapper.xml
    路径:src/main/resources/mybatis/mapper/DeptMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--核心配置文件-->
<mapper namespace="com.xxx.springcloud.dao.DeptDao">
    <!--增加一个部门-->
    <insert id="addDept" parameterType="com.xxx.springcloud.pojo.Dept">
        insert into dept (dname, db_source)
        values (#{dname}, DATABASE())
    </insert>
    <!--根据id查询部门信息-->
    <select id="queryById" resultType="com.xxx.springcloud.pojo.Dept">
        select deptno, dname, db_source
        from dept
        where deptno = #{deptno};
    </select>
    <!--查询所有的部门信息-->
    <select id="queryAll" resultType="com.xxx.springcloud.pojo.Dept">
        select deptno, dname, db_source
        from dept;
    </select>
</mapper>


  1. 创建service 接口类
    路径:src/main/java/com/xxx/springcloud/service/DeptService.java
package com.xxx.springcloud.service;

import com.xxx.springcloud.pojo.Dept;

import java.util.List;

public interface DeptService {
    //添加一个部门
    public boolean addDept(Dept dept);

    //根据id查出一个部门
    public Dept queryById(Long id);

    //查询所有部门信息
    public List<Dept> queryAll();
}

  1. 创建service实现类
    路径:com/xxx/springcloud/service/DeptServiceImpl.java
package com.xxx.springcloud.service;

import com.xxx.springcloud.dao.DeptDao;
import com.xxx.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    public DeptDao deptDao;

    @Override
    public boolean addDept(Dept dept) {
        return deptDao.addDept(dept);
    }

    @Override
    public Dept queryById(Long id) {

        return deptDao.queryById(id);
    }

    @Override
    public List<Dept> queryAll() {
        return deptDao.queryAll();
    }
}

  1. 创建controll类
    路径:src/main/java/com/xxx/springcloud/controller/DeptController.java
package com.xxx.springcloud.controller;

import com.xxx.springcloud.pojo.Dept;
import com.xxx.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class DeptController{
    @Autowired
    private DeptService deptService;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept) {
        return deptService.addDept(dept);
    }

    @RequestMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id) {
        return deptService.queryById(id);
    }

    @RequestMapping("/dept/list")
    public List<Dept> queryAll() {
        return deptService.queryAll();
    }
}

  1. 创建启动类
    路径:src/main/java/com/xxx/springcloud/DeptProvider_8001.java
package com.xxx.springcloud;

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

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

  1. 访问
    路径:http://localhost:8001/dept/list 集合
    访问:http://localhost:8001/dept/get/1 详情
    在这里插入图片描述

4.4.3 springcloud-consumer-dept-80 Rest环境搭建,服务消费者

  1. 创建
    在这里插入图片描述
  2. 输入名称 springcloud-consumer-dept-80,完成
    在这里插入图片描述
  3. 导入pom依赖
    <!--服务消费者 80端口  maven项目。访问直接localhost/xxx/xx-->
    <artifactId>springcloud-consumer-dept-80</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <!--实体类+web-->
    <dependencies>
        <dependency>
            <groupId>com.xxx</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
  1. 配置类
    路径:src/main/java/com/xxx/springcloud/config/ConfigBean.java
package com.xxx.springcloud.config;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean { //配置类
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

  1. controller
    路径:src/main/java/com/xxx/springcloud/controller/DeptConsumerController.java
package com.xxx.springcloud.controller;

import com.xxx.springcloud.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptConsumerController {
    /**
     * 理解:消费者,不应该有service层~
     * RestTemplate .... 供我们直接调用就可以了! 注册到Spring中
     * (地址:url, 实体:Map ,Class<T> responseType)
     * <p>
     * 提供多种便捷访问远程http服务的方法,简单的Restful服务模板~
     */
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 服务提供方地址前缀
     * <p>
     * Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
     */
    private static final String REST_URL_PREFIX = "http://localhost:8001";
    //private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    /**
     * 消费方添加部门信息
     * @param dept
     * @return
     */
    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept) {
        // postForObject(服务提供方地址(接口),参数实体,返回类型.class)
        return Boolean.TRUE.equals(restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class));
    }
    /**
     * 消费方根据id查询部门信息
     * @param id
     * @return
     */
    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id) {
        // getForObject(服务提供方地址(接口),返回类型.class)
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
    }
    /**
     * 消费方查询部门信息列表
     * @return
     */
    @RequestMapping("/consumer/dept/list")
    public List<Dept> list() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
    }
}
  1. 启动类
    路径:src/main/java/com/xxx/springcloud/DeptConsumer_80.java
package com.xxx.springcloud;

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

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

5. Eureka服务注册中心

5.1 什么是Eureka

  • Netflix在涉及Eureka时,遵循的就是API原则.
  • Eureka是Netflix的有个子模块,也是核心模块之一。Eureka是基于REST的服务,用于定位服务,以实现云端中间件层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务注册与发现,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper.

5.2 原理理解

服务注册中心
在这里插入图片描述
在这里插入图片描述

三大角色

* Eureka Server:提供服务的注册与发现
* Service Provider:服务生产方,将自身服务注册到Eureka中,从而使服务消费方能狗找到
* Service Consumer:服务消费方,从Eureka中获取注册服务列表,从而找到消费服务

5.3 构建步骤<以4.3为项目基础>

1. Eureka Server 的创建

  1. 右击springcloud_parent 创建moudel->springcloud_01eureka_server
    在这里插入图片描述

  2. 路由查看
    在这里插入图片描述

  3. springcloud_01eureka_server的pom的配置


    <!--引入springboot的web依赖-->
     <dependencies>
        <!--引入springboot的web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入eureka server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
  1. springcloud_01eureka_server的配置文件的编写
    路径:src/main/resources/application.yml
# 默认端口号:8761
server:
  port: 8761
# Eureka配置
eureka:
  instance:
    # Eureka服务端的实例名字
    hostname: 127.0.0.1
  client:
    # 表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    # 让当前应用仅仅是服务注册中心
    register-with-eureka: false
    # fetch-registry如果为false,则表示自己为注册中心,客户端的化为 ture
    # 关闭eureka client的立即注册
    fetch-registry: false
    # Eureka监控页面~
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
# spring 配置
spring:
  application:
    # 服务名不能出现下划线,默认服务名不区分大小写,推荐大写
    name: EUREKASERVER
  1. springcloud_01eureka_server的启动类的创建
    路径:src/main/java/com/xxx/EurekaServerApplication.java
package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
//开启服务注册中心
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

  1. 启动
    在这里插入图片描述
  2. 访问:http://127.0.0.1:8761/
    在这里插入图片描述

2. Eureka Client的创建

基于业务开发出来的一个个微服务

  1. springcloud_02eureka_client的创建

在这里插入图片描述
2. 路由查看
在这里插入图片描述
3. pom配置


        <dependencies>
        <!--引入springboot的web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入eureka-client依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
  1. 配置文件
    路径:src/main/resources/application.yml
# 端口
server:
  port: 8989

# 服务名称
spring:
  application:
    name: EUREKACLIENT
# 指定服务注册中心地址 Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/


  1. 启动类
    路径:src/main/java/com/xxx/EurekaClintApplication.java
package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
//开启Eureka客户端
@EnableEurekaClient
public class EurekaClintApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaClintApplication.class, args);
    }
}


  1. 启动客户端
    在这里插入图片描述
  2. 查看服务端的路径监控
    路径:http://127.0.0.1:8761/
    已经成功注册到eureka
    在这里插入图片描述

3. Eureka 自我保护机制:好死不如赖活着

出现一下这句话,说明进入自我保护机制

在这里插入图片描述
在这里插入图片描述
详细内容可以参考下这篇博客内容:https://blog.csdn.net/wudiyong22/article/details/80827594
在这里插入图片描述

在这里插入图片描述
服务端配置测试
在这里插入图片描述
在这里插入图片描述
客户端配置测试
在这里插入图片描述
加快统计时间,用最短的时间清除自我保护
在这里插入图片描述

4. Eureka Server 集群搭建

在这里插入图片描述

  1. 点击修改配置
    在这里插入图片描述

  2. 复制server项目,配置vm-Dserver.port=8762-Dserver.port=8763-Dserver.port=8764等如下图多个项目端口号
    在这里插入图片描述

  3. 启动这四个服务,都正常启动

在这里插入图片描述
4. 停止服务,配置本地hosts
路径:C:\Windows\System32\drivers\etc
在这里插入图片描述
5. 配置hosts

注意:最好通过软件修改,如果手动打开文件修改可能不生效或者保存失败

127.0.0.1   eureka8761.com
127.0.0.1   eureka8762.com
127.0.0.1   eureka8763.com

在这里插入图片描述

  1. 配置服务端8761集群
    路径:springcloud_01eureka_server\src\main\resources\application.yml
server:
  port: 8761
#Eureka配置
eureka:
  instance:
    hostname: eureka8761.com #Eureka服务端的实例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
    service-url: #监控页面~
      #重写Eureka的默认端口以及访问路径 --->http://localhost:8761/eureka/
      # 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(关联):8761关联87628763
      defaultZone: http://eureka8762.com:8762/eureka/,http://eureka8763.com:8763/eureka/

两个节点,当前运行时8761
在这里插入图片描述
7. 配置服务端8762集群
路径:springcloud_01eureka_server\src\main\resources\application.yml

server:
  port: 8762
#Eureka配置
eureka:
  instance:
    hostname: eureka8762.com #Eureka服务端的实例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
    service-url: #监控页面~
      #重写Eureka的默认端口以及访问路径 --->http://localhost:8761/eureka/
      # 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(关联):8762关联87618763
      defaultZone: http://eureka8761.com:8761/eureka/,http://eureka8763.com:8763/eureka/
  1. 配置服务端8763集群
    路径:springcloud_01eureka_server\src\main\resources\application.yml
server:
  port: 8763
#Eureka配置
eureka:
  instance:
    hostname: eureka8763.com #Eureka服务端的实例名字
  client:
    register-with-eureka: false #表示是否向 Eureka 注册中心注册自己(这个模块本身是服务器,所以不需要)
    fetch-registry: false #fetch-registry如果为false,则表示自己为注册中心
    service-url: #监控页面~
      #重写Eureka的默认端口以及访问路径 --->http://localhost:8761/eureka/
      # 单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      # 集群(关联):8763关联87628761
      defaultZone: http://eureka8761.com:8761/eureka/,http://eureka8762.com:8762/eureka/
  1. 客户端配置文件
    路径:springcloud_02eureka_client\src\main\resources\application.yml
# 端口
server:
  port: 8989

# Eureka配置:配置服务注册中心地址
# Eureka配置:配置服务注册中心地址
eureka:
  client:
    service-url:
      # 注册中心地址8761-8763
      defaultZone: http://eureka8761.com:8761/eureka/,http://eureka8762.com:8762/eureka/,http://eureka8763.com:8763/eureka/


  1. 运行客户端访问路由
    访问:http://eureka8761.com:8761/
    在这里插入图片描述

访问:http://eureka8762.com:8762/
在这里插入图片描述

访问:http://eureka8763.com:8763/
在这里插入图片描述

6. consul 服务注册中心

文档:https://www.consul.io/docs/architecture

1. consul Server 服务注册中心介绍和安装

  1. 选择下载:https://www.consul.io/downloads
    在这里插入图片描述

  2. 下载完成后生成如下文件
    在这里插入图片描述

  3. 压缩文件到指定位置,路径名称不要有中文
    在这里插入图片描述

  4. 在当前目录输入cmd,进入shell
    在这里插入图片描述

  5. 输入命令consul agent -dev
    在这里插入图片描述

  6. 访问counsul 界面,默认端口号8500, 路由:http://localhost:8500/
    在这里插入图片描述

  7. 管理中心介绍
    dc1:数据中心名称 datacenter 默认为 dc1
    在这里插入图片描述

  8. 指定数据中心名称启动:consul agent -dev -datacenter=aaa
    访问:http://localhost:8500/ 自动跳转到 http://localhost:8500/ui/aaa/services
    在这里插入图片描述

  9. 界面说明在这里插入图片描述
    在这里插入图片描述

  10. 配置环境变量
    查看当前exe的路径:E:\Java\springCloud\other\consul_1.13.2_windows_amd64
    在这里插入图片描述
    右键win在这里插入图片描述->应用和功能(F)->搜索环境变量,最后编辑path,全部点击确定
    在这里插入图片描述
    添加完成后,任意位置都可以打开consul 了
    在这里插入图片描述

2. consul client 服务客户端(微服务)

3. 新增model<以5.3为项目基础>

  1. 新增springcloud_03consulclient ,路由
    在这里插入图片描述
  2. pom.xml 引入依赖
 <!--引入依赖-->
  <!--引入依赖-->
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--consul-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
    </dependencies>
  1. 文件配置
    路径:springcloud_03consulclient\src\main\resources\application.yml
# 端口
server:
  port: 8082
# 指定名称
spring:
  application:
    name: CONSULCLIENT
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name} # 注册服务名称
# consul server 服务注册地址

  1. 启动类创建
    路径:src/main/java/com/xxx/ConsulClientApplication.java
package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;


@SpringBootApplication
// 开启consul ,jk
@EnableDiscoveryClient
public class ConsulClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsulClientApplication.class, args);

    }
}

  1. 启动

在这里插入图片描述
在这里插入图片描述
6. pom.xml 引入健康检查的依赖

  <!--健康检查依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  1. 启动
    在这里插入图片描述
  2. 断开后consul就直接消失了,说明没有自我保护机制
    在这里插入图片描述

7. 服务间通信和RestTemplate的使用

在这里插入图片描述

users Model 和 orders model 同步进行创建配置,最后进行通信,因为是user调用order,所以要先有order,user在调用。

1. 创建users Model<以6.3为项目基础>

名称:springcloud_04users
在这里插入图片描述
路由查看
在这里插入图片描述
pom.xml 依赖引入

  <!--引入依赖-->
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--consul-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--健康检查依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

application.yml配置

# 端口
server:
  port: 8888
# 指定名称
spring:
  application:
    name: USER
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name} # 注册服务名

UsersApplication启动类创建

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
// 开启consul ,jk
@EnableDiscoveryClient
public class UsersApplication {
    public static void main(String[] args) {
        SpringApplication.run(UsersApplication.class, args);
    }
}

启动运行,先开启的两个服务,再查看的服务管理,所有两个都有
在这里插入图片描述
创建controller:src/main/java/com/xxx/controller/UserController.java

package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;


@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    /**
     * 调用demo
     */
    @GetMapping("user")
    public String invokeDemo() {
        System.out.println("user demo");
        //调用order 订单服务,http://localhost:9999/order 接收返回值
        RestTemplate restTemplate = new RestTemplate();
        String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class);
        log.info("调用顶层服务成功:{}", orderResult);
        return "调用order服务成功,结果为:" + orderResult;
    }
}

启动程序并访问:http://localhost:8888/user
在这里插入图片描述

2. 创建orders Model

名称:springcloud_05orders
在这里插入图片描述
路由查看
在这里插入图片描述
pom.xml 依赖引入

  <!--引入依赖-->
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--consul-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--健康检查依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

application.yml配置

# 端口
server:
  port: 9999
# 指定名称
spring:
  application:
    name: ORDER
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name} # 注册服务名称

OrdersApplication启动类创建

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
// 开启consul ,jk
@EnableDiscoveryClient
public class OrdersApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrdersApplication.class, args);
    }
}

启动运行,先开启的两个服务,再查看的服务管理,所有两个都有
在这里插入图片描述创建controller:src/main/java/com/xxx/controller/OrderController.java

package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {
    private static final Logger log = LoggerFactory.getLogger(OrderController.class);

    @Value("${server.port}")
    private int port;

    /**
     * 调用demo
     */
    @GetMapping("order")
    public String demo() {
        log.info("order demo.....");
        return "order demo ok ,当前提供服务端口为:" + port;
    }
}



启动程序并访问:http://localhost:9999/order
在这里插入图片描述

8. Ribbon:负载均衡(基于客户端)

Ribbon:只能负载均衡不能发送请求
RestTemplate:发送请求

1.负载均衡以及Ribbon

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

2. Ribbon的服务调用说明

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

3. Ribbon的服务调用实例

配置里面复制order,新建order9990
在这里插入图片描述

1. DiscoveryClient 的实现

服务注册与发现客户端对象,需要自己写策略

路径: springcloud_04users\src\main\java\com\xxx\controller\UserController.java

package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;


@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    @Autowired //服务注册与发现客户端对象
    private DiscoveryClient discoveryClient;

    /**
     * 调用demo
     */
    @GetMapping("user")
    public String invokeDemo() {
        //1. 调用order 订单服务,http://localhost:9999/order 接收返回值
        //RestTemplate restTemplate = new RestTemplate();
        //String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class);

        //2. 调用ribbon组件+restTemplate 实现负载均衡的调用 1. DiscoveryClient 2. LoadBalanceClient 3.LoadBalance
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances("ORDER");
        serviceInstances.forEach(serviceInstance -> {
            log.info("服务机:{} 服务端口:{} 服务地址:{}", serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri());
        });
      /*  log.info("调用顶层服务成功:{}", orderResult);
        return "调用order服务成功,结果为:" + orderResult;*/
        return "user ok";
    }
}

运行:http://localhost:8888/user ,发现返回两个接口的数据
在这里插入图片描述

2. LoadBalancerClient 的实现

负载均衡客户端对象,轮询策略

路径: springcloud_04users\src\main\java\com\xxx\controller\UserController.java

package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;


@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    @Autowired //服务注册与发现客户端对象,需要自己写策略
    private DiscoveryClient discoveryClient;
    @Autowired //负载均衡客户端对象,轮询策略
    private LoadBalancerClient loadBalancerClient;

    /**
     * 调用demo
     */
    @GetMapping("user")
    public String invokeDemo() {
        //1. 调用order 订单服务,http://localhost:9999/order 接收返回值
        //RestTemplate restTemplate = new RestTemplate();
        //String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class);

        //2. 调用ribbon组件+restTemplate 实现负载均衡的调用 1. DiscoveryClient 2. LoadBalancerClient 3.LoadBalance
       /* List<ServiceInstance> serviceInstances = discoveryClient.getInstances("ORDER");
        serviceInstances.forEach(serviceInstance -> {
            log.info("服务机:{} 服务端口:{} 服务地址:{}", serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri());
        });
        String forObject = new RestTemplate().getForObject(serviceInstances.get(0).getUri() + "/order", String.class);
       */
        // 3. 使用LoadBalancerClient 进行服务调用 轮询策略
        ServiceInstance serviceInstance = loadBalancerClient.choose("ORDER");
        log.info("服务机:{} 服务端口:{} 服务地址:{}", serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri());
        String forObject = new RestTemplate().getForObject(serviceInstance.getUri() + "/order", String.class);
      /*  log.info("调用顶层服务成功:{}", orderResult);
        return "调用order服务成功,结果为:" + orderResult;*/
        return "user ok" + forObject;
    }
}

访问:http://localhost:8888/user ,查看服务端信息

服务机:localhost 服务端口:9990 服务地址:http://localhost:9990

在这里插入图片描述
再次访问:http://localhost:8888/user ,查看服务端信息

服务机:localhost 服务端口:9999 服务地址:http://localhost:9999

在这里插入图片描述

3. @LoadBalanced 的实现

  1. 创建配置类BeansConfig
    路径:springcloud_04users\src\main\java\com\xxx\config\BeansConfig.java
package com.xxx.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration //代表这是一个springboot 配置类  spring.xml
public class BeansConfig {

    //在工厂中创建restTemplate
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

  1. 修改控制器: springcloud_04users\src\main\java\com\xxx\controller\UserController.java
package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;


@RestController
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);

    @Autowired //服务注册与发现客户端对象,需要自己写策略
    private DiscoveryClient discoveryClient;
    @Autowired //负载均衡客户端对象,轮询策略
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 调用demo
     */
    @GetMapping("user")
    public String invokeDemo() {
        //1. 调用order 订单服务,http://localhost:9999/order 接收返回值
        //RestTemplate restTemplate = new RestTemplate();
        //String orderResult = restTemplate.getForObject("http://localhost:9999/order", String.class);

        //2. 调用ribbon组件+restTemplate 实现负载均衡的调用 1. DiscoveryClient 2. LoadBalancerClient 3.@LoadBalance
       /* List<ServiceInstance> serviceInstances = discoveryClient.getInstances("ORDER");
        serviceInstances.forEach(serviceInstance -> {
            log.info("服务机:{} 服务端口:{} 服务地址:{}", serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri());
        });
        String forObject = new RestTemplate().getForObject(serviceInstances.get(0).getUri() + "/order", String.class);
       */
        // 3. 使用LoadBalancerClient 进行服务调用 轮询策略
    /*    ServiceInstance serviceInstance = loadBalancerClient.choose("ORDER");
        log.info("服务机:{} 服务端口:{} 服务地址:{}", serviceInstance.getHost(), serviceInstance.getPort(), serviceInstance.getUri());
        String forObject = restTemplate.getForObject(serviceInstance.getUri() + "/order", String.class);*/
        // 4. 使用 @LoadBalanced注解调用
        String forObject = restTemplate.getForObject("http://ORDER/order", String.class);
      /*  log.info("调用顶层服务成功:{}", orderResult);
        return "调用order服务成功,结果为:" + orderResult;*/
        return "user ok" + forObject;
    }
}

  1. 访问:http://localhost:8888/user
    在这里插入图片描述
    在这里插入图片描述

9. OpenFeign:负载均衡(基于服务端)

网页:https://spring.io/projects/spring-cloud-openfeign

9.1 简介

在这里插入图片描述

9.2 开发

1. 关闭所有服务

在这里插入图片描述

2. 开启consul :consul agent -dev

在这里插入图片描述

3. 查看consul是否运行正常

路径:http://localhost:8500/ui/dc1/services
在这里插入图片描述

4. 创建类别model->springcloud_06category

在这里插入图片描述
pom.xml

  <!--引入依赖-->
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--consul-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--健康检查依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

application配置:src/main/resources/application.yml

# 端口
# 端口
server:
  port: 8787
spring:
  application:
    name: CATEGORY
  cloud:
    consul:
      host: localhost
      port: 8500

创建启动文件:src/main/java/com/xxx/CategoryApplication.java

package com.xxx;

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

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

启动服务查看consul:http://localhost:8500/ui/dc1/services
在这里插入图片描述
创建控制类:src/main/java/com/xxx/controller/CategoryController.java

package com.xxx.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Value("${server.port}")
    private int port;
    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        return "category ok,类别服务提供的端口为:" + port;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
pom.xml 添加openfeign

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

启动类开启openFeign

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient//开启服务注册
@EnableFeignClients//开启openFeign的调用
public class CategoryApplication {
    public static void main(String[] args) {
        SpringApplication.run(CategoryApplication.class, args);
    }
}

创建配置:src/main/java/com/xxx/feignclient/ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {
    //调用商品服务
    @GetMapping("/product")
    public String product();
}

修改控制器:src/main/java/com/xxx/controller/CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        String product = productClient.product();
        return "category ok !!!" + product;
    }
}

启动,访问路径:http://localhost:8787/category
在这里插入图片描述
测试:product添加了一个list方法,这边修改ProductClient

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {
    //调用商品服务
    @GetMapping("/product")
    public String product();
    @GetMapping("/list")
    public String list();
}

测试:修改controller

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        String product = productClient.product();
        String list = productClient.list();
        log.info("结果1:{}",product);
        log.info("结果2:{}",list);
        return "category ok !!! ===>product:" + product+" ===>list:"+list;
    }
}

访问路径:http://localhost:8787/category
在这里插入图片描述

5. 创建产品model->springcloud_07product

在这里插入图片描述
pom.xml

 <!--引入依赖-->
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--consul-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--健康检查依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

application配置:src/main/resources/application.yml

# 端口
# 端口
server:
  port: 8788
spring:
  application:
    name: PRODUCT
  cloud:
    consul:
      host: localhost
      port: 8500

创建启动文件:src/main/java/com/xxx/ProductApplication.java

package com.xxx;

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

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

启动服务查看consul:http://localhost:8500/ui/dc1/services
在这里插入图片描述
创建控制类:src/main/java/com/xxx/controller/ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    @GetMapping("/product")
    public String product() {
        log.info("进入商品服务....");
        return "product ok,商品服务提供的端口为:" + port;
    }


}

访问:http://localhost:8788/product
在这里插入图片描述
pom.xml 添加openfeign

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

启动类开启openFeign

package com.xxx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient//开启服务注册
@EnableFeignClients//开启openFeign的调用
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}

controller 添加方法:src/main/java/com/xxx/controller/ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    @GetMapping("/product")
    public String product() {
        log.info("进入商品服务....");
        return "product ok,商品服务提供的端口为:" + port;
    }

    @GetMapping("/list")
    public String list() {
        log.info("进入商品列表服务....");
        return "list ok,商品列表服务提供的端口为:" + port;
    }
}

6. 参数传递 对象和零散数据

在这里插入图片描述

1. 零散类型querySting

querySting:test?name=zs&age=11

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    // 零散类型 querySting test?name=zs&age=11
    @GetMapping("/test")
    public String test(@RequestParam("name") String name, @RequestParam("age") Integer age) {
        log.info("name:{}   age:{}", name, age);
        return "test ok, 当前服务端口为:" + port;

      }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    //调用商品服务
    @GetMapping("/test")
    public String test(@RequestParam("name") String name, @RequestParam("age") Integer age);
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        String zs = productClient.test("zs", 11);
        return "category ok !!!   " + zs;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
查看ProductController运行界面,已经接收到
在这里插入图片描述

2. 零散类型 路由传参

路由传参:test1/1/zs

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    // 零散类型 路径传参 test1/zs/11
    @GetMapping("/test1/{id}/{name}")
    public String test1(@PathVariable("id") Integer id, @PathVariable("name") String name) {
        log.info("id:{}   name:{}", id, name);
        return "test1 ok, 当前服务端口为:" + port;

     }
  }
 

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    //调用商品服务
 
    // 零散类型 路径传参 test1/zs/11
    @GetMapping("/test1/{id}/{name}")
    public String test1(@PathVariable("id") Integer id, @PathVariable("name") String name);

    @GetMapping("/product")

}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        String zs = productClient.test1(1, "zs");
        return "category ok !!!   " + zs;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
查看ProductController运行界面,已经接收到
在这里插入图片描述

3. 对象传递

form 表单 ---------------> 参数加 @RequestPart ,文件上传的时候可以用
application/json--------> 参数加 @RequestBody

Product实体类:springcloud_07product\src\main\java\com\xxx\pojo\Product.java

package com.xxx.pojo;

import java.util.Date;

public class Product {
    private Integer id;
    private String name;
    private Double price;
    private Date bir;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Date getBir() {
        return bir;
    }

    public void setBir(Date bir) {
        this.bir = bir;
    }
    public Product() {
    }

    public Product(Integer id, String name, Double price, Date bir) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.bir = bir;
    }
    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", bir=" + bir +
                '}';
    }
}

Category实体类:springcloud_06category\src\main\java\com\xxx\pojo\Product.java

package com.xxx.pojo;

import java.util.Date;

public class Product {
    private Integer id;
    private String name;
    private Double price;
    private Date bir;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Date getBir() {
        return bir;
    }

    public void setBir(Date bir) {
        this.bir = bir;
    }

    public Product() {
    }

    public Product(Integer id, String name, Double price, Date bir) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.bir = bir;
    }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", bir=" + bir +
                '}';
    }
}

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import com.xxx.pojo.Product;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;
    // 对象类型
    @PostMapping("/test3")
    public String test3(@RequestBody Product product) {
        log.info("product:{} ", product);
        return "test3 ok, 当前服务端口为:" + port;

    }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import com.xxx.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    //调用商品服务
    // 对象类型
    @PostMapping("/test3")
    public String test3(@RequestBody Product product);

}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import com.xxx.pojo.Product;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
        String zs = productClient.test3(new Product(1, "zs", 23.3, new Date()));
        return "category ok !!!   " + zs;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
查看ProductController运行界面,已经接收到
在这里插入图片描述

7. 参数传递 数组和集合数据

1. 数组传递

querySting方式:test?name=zs&age=11

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    // 数组类型 queryString test4?name=zs&age=11
    @GetMapping("/test4")
    public String test4(@RequestParam("ids") String[] ids) {
        for (String id : ids) {
            log.info("id:{} ", id);
        }
          //转为list集合
        List<String> strings = Arrays.asList(ids);
        return "test4 ok, 当前服务端口为:" + port;

    }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    // 数组类型 queryString test4?name=zs&age=11
    @GetMapping("/test4")
    public String test4(@RequestParam("ids") String[] ids);
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
      	String result = productClient.test4(new String[]{"11", "22", "33", "44"});
        return "category ok !!!   " + result;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
查看ProductController运行界面,已经接收到
在这里插入图片描述

2. 集合传递

oo(oriented 面向 object 对象):面向对象
vo(value 值 object 对象):用来传递数据对象称之为值对象
dto(data 数据 transfer 传输 object 对象):数据传输对象
传递:以数组传递 。
接收:以 值对象vo 接收。

Product创建vo对象:springcloud_07product\src\main\java\com\xxx\vos\CollectionVO.java

package com.xxx.vos;

import java.util.List;

//定义用来接收集合类型参数对象
public class CollectionVO {
    private List<String> ids;

    public List<String> getIds() {
        return ids;
    }

    public void setIds(List<String> ids) {
        this.ids = ids;
    }
}

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

  // 集合列表
    // oo(oriented 面向  object 对象):面向对象    vo(value 值 object 对象):用来传递数据对象称之为值对象
    // dto(data 数据 transfer 传输 object 对象):数据传输对象
    @PostMapping("/test5")
    public String test5(CollectionVO collectionVO) {
        collectionVO.getIds().forEach(id -> log.info("id:{}", id));
        return "test5 ok, 当前服务端口为:" + port;
     }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    // 集合列表
    @PostMapping("/test5")
    public String test5(@RequestParam("ids") String[] ids);
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public String category() {
        log.info("进入类别服务....");
      	    String result = productClient.test5(new String[]{"11", "22", "33", "44"});
        return "category ok !!!   " + result;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
查看ProductController运行界面,已经接收到
在这里插入图片描述

8. 调用服务响应处理

1. 根据id查询对象信息

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

 // 定义一个接口接收id类型参数,返回一个基于id查询的对象
    @GetMapping("/product/{id}")
    public Product product(@PathVariable("id") Integer id) {
        log.info("id:{} ", id);
        return new Product(1, "十四", 23.5, new Date());
     }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


    //根据id查询商品
    @GetMapping("/product/{id}")
    public Product product(@PathVariable("id") Integer id);
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public Product category() {
        log.info("进入类别服务....");
      	 Product result = productClient.product(1);
        return result;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述

2. 根据id查询对象列表信息

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

  // 定义一个接口接收类型id类型参数,返回一个基于id查询的list对象
    @GetMapping("/products")
    public List<Product> finProductsByCategoryId(@RequestParam("categoryId") Integer categoryId) {
        log.info("categoryId:{} ", categoryId);
        List<Product> productList = new ArrayList<>();
        productList.add(new Product(1, "十四", 24.5, new Date()));
        productList.add(new Product(2, "十五", 25.5, new Date()));
        productList.add(new Product(3, "十六", 26.5, new Date()));
        return productList;
        //return new Product(1, "十四", 23.5, new Date());
     }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


  // 定义一个接口接收类型id类型参数,返回一个基于id查询的list对象
    @GetMapping("/products")
    public List<Product> finProductsByCategoryId(@RequestParam("categoryId") Integer categoryId) ;
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public List<Product> category() {
        log.info("进入类别服务....");
   
        List<Product> products = productClient.finProductsByCategoryId(1);
        return products;
    }
}

访问:http://localhost:8787/category
在这里插入图片描述

3. 根据id查询对象列表信息分页

ProductController :springcloud_07product\src\main\java\com\xxx\controller\ProductController.java

package com.xxx.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Value("${server.port}")
    private int port;

    // 定义一个接口接收类型id类型参数,返回一个基于id查询的list对象
    @GetMapping("/productsPage")
    public Map<String, Object> finProductsByCategoryIdAndPage(@RequestParam("page") Integer page, @RequestParam("pageNum") Integer pageNum, @RequestParam("categoryId") Integer categoryId) {
        log.info("当前页:{}   每页数量:{}   categoryId:{} ", page, pageNum, categoryId);
        Map<String, Object> map = new HashMap<>();
        List<Product> productList = new ArrayList<>();
        productList.add(new Product(1, "十四", 24.5, new Date()));
        productList.add(new Product(2, "十五", 25.5, new Date()));
        productList.add(new Product(3, "十六", 26.5, new Date()));
        map.put("row", productList);
        map.put("total", 50);
        return map;
    }
  }

ProductClient:springcloud_06category\src\main\java\com\xxx\feignclient\ProductClient.java

package com.xxx.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

//调用商品服务接口
@FeignClient(value = "PRODUCT")//value:用来书写调用服务的id
public interface ProductClient {


   // 定义一个接口接收类型id类型参数,返回一个基于id查询的list对象,并返回分页信息
    @GetMapping("/productsPage")
    public Map<String, Object> finProductsByCategoryIdAndPage(@RequestParam("page") Integer page, @RequestParam("pageNum") Integer pageNum, @RequestParam("categoryId") Integer categoryId);
}

CategoryController:springcloud_06category\src\main\java\com\xxx\controller\CategoryController.java

package com.xxx.controller;

import com.xxx.feignclient.ProductClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CategoryController {
    private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
    @Autowired
    private ProductClient productClient;

    @GetMapping("/category")
    public  Map<String, Object>  category() {
        log.info("进入类别服务....");
    	Map<String, Object> map = productClient.finProductsByCategoryIdAndPage(1, 10, 1);
        int total = (int) map.get("total");
        List<Product> row = (List<Product>) map.get("row");
        System.out.println(total);
        System.out.println(row);
        return map;
       
    }
}

访问:http://localhost:8787/category
在这里插入图片描述
CategoryController 查看打印的数据
在这里插入图片描述

9.3 细节

openfeign默认调用时间为1秒,超时报错,如下图。可以通过修改超时时间,处理.

在这里插入图片描述

路径:springcloud_06category\src\main\resources\application.yml

# 端口
server:
  port: 8787
spring:
  application:
    name: CATEGORY
  cloud:
    consul:
      host: localhost
      port: 8500
# 配置类别调用商品服务openfeign 默认 超时时间 默认1s 现在改为5秒。PRODUCT:指定的服务名称
feign:
  client:
    config:
      PRODUCT:
        connect-timeout: 5000
        read-timeout: 5000
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值