万字总结springcloud

SpringCloud

1.SpringCloud介绍

1.1为什么会有SpringCloud

​ 1>微服务概述

​ 微服务是什么? 以前一个模块中有所有的功能 ; 而微服务是一个模块负责一个功能,甚至可以有自己的单独的数据库
​ 其所使用的是http的restful轻量级的机制进行通信的
​ 以前是将商品/订单/交易/…都打war包,一个出问题,全部都会受影响
​ 微服务是各个模块独立出来,独立部署,各个服务是一个单独的进程,一个模块不会影响到其它

​ 微服务特点: [1]拆分
​ [2]各自独立的进程
​ [3]拥有自己独立的数据库

​ 微服务架构

​ 引:springcloud和dubbo的区别: dubbo是基于http的rpc通信机制, spring cloud是restful通信机制

​ 2>微服务的优缺点

​ 优点:[1]服务足够小,易于理解
​ [2]开发简单,开发效率高,一个服务可能就是专一的只干一件事
​ [3]解耦合
​ [4]微服务只是业务逻辑代码,不会和html,css或其它界面混合
​ 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有统一的数据库

​ 缺点:[1]开发人员要处理分布式系统的复杂性
​ [2]多服务器运维难度,运维的压力增大
​ [3]系统部署依赖
​ [4]服务间通信成本

​ 3>为什么选择springcloud为微服务架构

​ 因为springcloud几乎涵盖了所有的微服务所需要的技术栈,如:负载均衡,配置服务,高可用容错等等

1.2springcloud包括什么

​ springcloud是基于springboot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件

​ springcloud=分布式微服务框架下的一站式解决方案,是各个微服框架落地技术的集合体,俗称微服务全家桶

1.3springcloud和springboot

​ springboot就相当于出一个个微服务,springcloud将其连接起来

​ springboot可以独立使用,cloud必须依赖

​ springboot专注于快速,方便的开发单个微服务个体,springcloud关注全局的服务治理框架

1.4springcloud和dubbo

image-20211019155750422

​ 区别:[1]dyubbo rpc远程调用,springcloud是基于http的rest,相比之下rest要比rpc更加的灵活,不存在代码级别的依赖
​ [2]品牌机和组装机的区别
​ springcloud的功能比dubbo更加强大,涵盖面更广,它能与其它的spring项目完美的融合
​ dubbo的选择自由度很高,但是自由度很高的同时也面临着单一环节出现问题全部都可能受影响
​ [3]社区支持与更新力度
​ springcloud的火热程度和力度都要明显高于dubbo
​ [4]两者所解决的问题域不一样,dubbo的定位是一款RPC框架,而springcloud的目标是微服务架构下的一站式解决方 案,在面临微服务基础框架选型时dubbo和springcloud只能二选一

1.5springcloud网站

​ 官网:http://projects.spring.io/springcloud/

​ 参考书:https://springcloud.cc/spring-cloud-netflix.html

​ API说明:http://springcloud.cc/spring-cloud-dalston.html

​ springcloud中国社区:http://springcloud.cn

​ springcloud中文网: https://springcloud.cc

2. springcloud入门

​ 1>一个简单的模板(传统的)

​ 步骤:
​ [1]创建两个springboot的工程,一个作为consumer,一个作为provider
​ [2]在provider工程中创建一个controller类,在其上面加@RestController注解(该注解是Controller和ResponseBody的结
​ 合)在springboot的核心配置文件中声明tomcat的端口号
​ [3]在consumer工程中创建一个controller类,也在其上面加@RestController注解
​ 创建一个方法,在这个方法中new一个RestTemplate对象
​ 用该对象调用getForEntity(url=“服务提供者的网址”,服务提供者返回的类型.class),设置一个返回值
​ 用返回值.getStatusCode()获取响应的编码,例如200或404等
​ 用返回值.getHeaders()获取响应的头
​ 用返回值.getBody()获取响应的结果
​ 说明:[1]RestTemplate 是一个基于Http协议的一个工具对象,我们可以利用这个对象,以http协议发送到某个web服务器中
​ 在springcloud中可以利用这个对象来访问服务提供者
​ 这个对象可以new,也可以交给spring来创建
​ [2]getForEntity有三个返回值,参数三为可变的Object类型的数据,表示本次请求中的url参数数据
​ [3]getForEntity的返回值对象是ResponseEntity类型的

​ 2>一个简单的模板(注解式的)

​ 步骤:
​ [1]前两步都和1>的前两步一样,第三步中不要new对象
​ [2]创建一个额外的RestTemplateConfig类,在其内部定义一个返回值为RestTemplate的方法,并在方法上加bean注解,
​ 在其类上面加Configuration注解
​ [3]然后就可以在consumer类中利用注解的方式将新建的对象赋值给RestTemplate 对象

3.注册中心Eureka

3.1定义

​ Eureka和zookeeper有点类似,都是注册中心

image-20211020165017264

优点: Eureka支持集群,在微服务框架的这种分布式系统中,我们要充分考虑各个微服务组件的高可用性问题,不能由单点故 障,由于注册中心Eureka本身也是一个服务,如果它只有一个节点,那么它有可能发生故障,这样我们就不能注册与查询 的服务了,所以我们需要一个高可用的服务注册中心,这就需要通过Eureka的集群来解决
Eureka Server的高可用实际上就是将自己作为服务向其它服务中心注册自己,这样就会形成一组互相注册的服务注册
中心,进而实现服务清单的互相同步

3.2 Euraka与zookeeper

​ 1> CAP理论:C(一致性), A(可用性), P(分区容错性)
​ 其中,分期容错性是必须保证的,因此我们只能在A和C之间进行权衡,zookeeper保证的是CP,zookeeper是AP

​ 2> zookeeper的cp理论

​ 主服务器宕机

image-20211020165636735

​ 从服务器经过投票上位(时间可能很长,难以容忍)

image-20211020165920209

​ 3> Eureka的AP

​ Eureka不分主从,相互备份

image-20211020170354363

​ 第二次访问服务会随机访问,如果访问不到就会更换服务器访问服务器(因为服务的同步需要时间)

image-20211020170633913

​ 如果有一个宕机了,那么就不会访问该注册中心,并且当02恢复以后,会迅速的同步服务信息,即使在同步信息期间访问02
​ ,也会因找不到服务而更换服务器

image-20211020171016429

3.3 使用 Eureka

​ 步骤:

​ [1]创建一个springboot的工程,作为注册中心
​ [2]添加依赖springcloud,依赖管理器,依赖
​ 指明sprigncloud的版本号
​ [3]在main方法 加注解 EnableEurekaServer激活eureka
​ [4]配置springboot核心配比文件
​ 指定tomvcat内置端口号
​ 域名
​ 要不要在组测中心注册自己
​ 是否减少服务
​ 注册中心的位置
​ [5]测试:在浏览器中输入localhost:端口号

​ [6]再创建一个服务的提供者
​ [7]添加依赖管理器,修改依赖为springcloud-client,添加Eureka的依赖
​ [8]main 注解EnableEurekaClient
​ [9]创建一个controller类,里面的方法作为服务提供者的方法
​ [10]配置springboot核心配置文件:指明自己的端口号,著名自己的服务名称(唯一性),指明Eureka 的服务地址
​ [11]启动服务 , 可以在网页看到注册成功

​ [12]再创建一个工程,作为consumer
​ [13]修改pom文件添加springcloud的依赖和Eureka的依赖,并添加依赖管理器使得springcloud的依赖生效
​ 配置springboot 的核心配置文件,指明端口号,以及服务名称(唯一性),指明Eureka的服务地址
​ [14]main中注解@EnableEurekaClient
​ [15]在config类中加一个注解(由于使用了Eureka的注册中心,所以必须加这个注解才能使用服务)

​ 注:可能遇到的问题:关于springcloud和springboot的版本冲突的问题
​ 如果在maven中更新版本还是报错,且会影响maven的clear,install等一系列的操作
​ 解决办法就是在创建一个springboot工程的时候让idea自动指定springcloud的版本,操作如下:
image-20211025183808217

image-20211025183830492

image-20211025183933312

3.4负载均衡Ribbon

​ ribbon和nginx有点类似,都是用于负载均衡的,在springcloud中 , 当用服务的名称时,即调用方法
​ restTemplate.getForEntity(“http://SPRINGCLOUD03-EUREKA-PROVIDER/test”, String.class) 时,
​ 就必须使用ribbon负载均衡,否则就会报错

image-20211025201045314

eureka服务注册中心

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud02-eureka</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

application.properties

#???tomcat???
server.port=9100
#?????????hostname
eureka.instance.hostname=localhost
#??????????????????,????????,?????,????????????
eureka.client.register-with-eureka=false
#???????????,???????????????????,???????????
eureka.client.fetch-registry=false
#?????????
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka

main方法

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud02EurekaApplication {

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

}

erureka的provider

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud03-Eureka-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>

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

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

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

    </dependencies>

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

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

</project>

application.properties

#??????,??????????????
spring.application.name=springcloud03-Eureka-provider
#??eureka?????
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#??tomcat????????????tomcat??????
server.port=8081

Controller

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyConreoller {

    @RequestMapping("/test")
    public String test(){
        return "使用Eureka的服务提供者";
    }

}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud03EurekaProviderApplication {

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

}

eureka的consumer

#??????,??????????????
spring.application.name=springcloud04-Eureka-consumer
#??eureka?????
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#??tomcat????????????tomcat??????
server.port=8080

MyController

package com.wang.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/test")
    public String test(){
        //RestTemplate restTemplate = new RestTemplate();
        /*
        * 通过注册中心发现服务并访问服务器,其中SPRINGCLOUD03-EUREKA-PROVIDER就是在注册中心的名称(不区分大小写)
        * springcloud会跟根据这个服务名到注册中心获取服务所对应的服务所在IP+端口号,然后利用ResTemlate访问服务
        * */
        ResponseEntity<String> result = restTemplate.getForEntity("http://SPRINGCLOUD03-EUREKA-PROVIDER/test", String.class);
        //  [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20", Date:"Wed, 20 Oct 2021 01:47:43 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }
}

conf

package com.wang.springcloud.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
public class RestTemplateConfig {

    /*
    * 在spring的应用上下文中定义一个Rest模板对象
    * @LoadBalanced 注解用于标记当前的RestTemplate使用Ribbon的负载均衡访问服务的提供者
    * 当使用了Eureka注册中心后必须使用这个注解否则无法正常获取服务,默认情况Ribbon的负载均衡的策略是
    * 轮询的
    * */
    @Bean
    @LoadBalanced
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud04EurekaConsumerApplication {

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

}

3.5Eureka的集群

​ 步骤:
​ [1]创建一个springobot工程,集成springcloud,在pom文件中添加Eureka的server依赖
​ 在springboot的核心配置文件中指明ip端口号为9100 , 指明9200Eureka,配置自己的服务名称
​ [3]再创建一个springcloud集成springcloud工程,在pom文件中添加Euerka的server依赖
​ 在springboot的核心配置文件中指明ip端口号为9200 , 指明9100Eureka,配置自己的服务名称
​ 在main方法加注解
​ [4]在host文件中配置9100和9200指向的ip地址都是127.0.0.1
​ 分别启动9100和9200
​ [5]创建一个工程,作为服务提供者
​ 在springboot核心配置文件中指明多个Eureka的注册中心:eureka会随机选择一个进行注册,然后互相同步
​ [6]创建一个工程,作为服务的消费者
​ 在springboot核心配置文件中指明多个Eureka的注册中心: eureka会随机选择一个进行注册,然后互相同步

9100的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud05-Eureka-cluster-server9100</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

application.properties

server.port=9100
eureka.instance.hostname=eureka9100
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://eureka9200:9200/eureka

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud05EurekaClusterServer9100Application {

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

}

9200 application

server.port=9200
eureka.instance.hostname=eureka9200
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://eureka9100:9100/eureka

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class SpringcloudEurekaClusterServer9200Application {

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

}

provider的pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud07-Eureka-cluster-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

springboot的配置文件

#指名服务的名称(唯一性)
spring.application.name=springcloud07-Eureka-cluster-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://eureka9100:9100/eureka,http://eureka9200:9200/eureka
#配置tomcat的服务的端口号
server.port=8081

controller

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public String test(){
        return "这是一个eureka集群的服务提供者";
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud07EurekaClusterProviderApplication {

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

}

consumer的核心配置文件

#指明服务的名称(唯一性)
spring.application.name=springcloud08-Eureka-cluster-consumer
#指明eureka的服务注册中心
eureka.client.service-url.defaultZone=http://eureka9100:9100/eureka,http://eureka9200:9200/eureka
#指明tomcat的服务端口号
server.port=8080

controller

package com.wang.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/test")
    public String test(){
        //RestTemplate restTemplate = new RestTemplate();
        /*
        * 通过注册中心发现服务并访问服务器,其中SPRINGCLOUD03-EUREKA-PROVIDER就是在注册中心的名称(不区分大小写)
        * springcloud会跟根据这个服务名到注册中心获取服务所对应的服务所在IP+端口号,然后利用ResTemlate访问服务
        * */
        ResponseEntity<String> result = restTemplate.getForEntity("http://springcloud07-Eureka-cluster-provider/test", String.class);
        //  [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20", Date:"Wed, 20 Oct 2021 01:47:43 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }
}

conf

package com.wang.springcloud.conf;

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
public class RestTemplateConfig {

    /*
    * 在spring的应用上下文中定义一个Rest模板对象
    * @LoadBalanced 注解用于标记当前的RestTemplate使用Ribbon的负载均衡访问服务的提供者
    * 当使用了Eureka注册中心后必须使用这个注解否则无法正常获取服务,默认情况Ribbon的负载均衡的策略是
    * 轮询的
    * */
    @Bean
    @LoadBalanced
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud08EurekaClusterConsumerApplication {

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

}

3.6Eureka的自我保护模式

​ 什么是Eureka的自我保护模式?

image-20211026091517042

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

​ Euerka是默认自动开启自我保护模式的,当然也可以手动关闭自我保护模式

​ 在EuerkaServer的配置文件中添加eureka.server.enable-self-preservation = false
​ 在Eureka的Provider和Consumer配置文件中添加如下配置:
​ //每间隔2s,向服务器段端发送一次心跳,证明自己依然存活
​ eureka.instance.lease-renewal-interval-in-second = 2
​ //告诉服务器端,如果我在10s之内没有发送心跳,就代表我故障了,将我踢出
​ eureka.instance.lease-expiration-duration-in-seconds = 10
​ 以上配置完成后,即可关闭自我保护模式

4.Ribbon

4.1定义

我们常说的负载均衡是指将一个请求均匀的分摊给不同的节点上执行,负载均衡分为硬件负载均衡个软件负载均衡:
硬件负载均衡有:F5,深信服,Arry等
软件负载均衡有:Nginx,LVS,HAProxy等

Ribbon是Neflix发布的开源项目,主要的功能是提供客户端的负载均衡算法,是一个基于HTTP和TCP的客户端负载均衡
的工具

在springcloud中,Ribbon主要与RestTemplate对象配合起来使用Ribbon会自动化配置RestTemplate对象,通过
@LoadBalanced开启RestTemplate对象调用的负载均衡

4.2Ribbon和Nginx

​ 二者的区别:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cHOJXd7K-1635942021545)(https://raw.githubusercontent.com/OneTimes1/photo/master/C:%5CUser%5C14330%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images202111032012862.png)]

4.3使用Ribbon

​ 1>正常的使用

​ 步骤:
​ [1]创建一个工程,作为注册中心
​ [2]再创建两个工程,作为服务的提供者
​ 修改两个工程的端口号
​ 两个工程的服务提供者的服务名一样
​ [3]创建一个工程,作为服务的消费者

​ 2>修改ribbon的负载均衡的策略

​ ribbon默认使用的是轮轮询的策略,但是在实际开发中,我们也可以修改其策略

image-20211026111142289

image-20211026111219807

​ 修改的方法:
​ 在conf文件中本来是直接创建了一个RestTemplate对象,
​ 在该类中再定义一个方法,其返回值为IRule类型的,在这个方法内部可以return new 指定的策略类;
​ 并在该方法上加一个@bean标签,把他交给springboot容器管理
​ (前提是在maven中已经导入ribbon-loadbalancer依赖)

服务注册中心

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud09-Eureka-ribbon</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>

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

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

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

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

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

</project>

核心配置文件

server.port=9100
eureka.instance.hostname=loaclhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:9100/eureka

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud09EurekaRibbonApplication {

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

}

8081provider

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud10-Eureka-ribbon-provider8081</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>

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

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

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

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

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

</project>

核心配置文件

#指名服务的名称(唯一性)
spring.application.name=springcloud10-Eureka-ribbon-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#配置tomcat的服务的端口号
server.port=8081

controller

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public String test(){
        return "这是一个ribbon下的8081服务提供者";
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud10EurekaRibbonProvider8081Application {

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

}

8082的controlelr

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public String test(){
        return "这是ribbon下的8082服务";
    }
}

核心配置文件

#指名服务的名称(唯一性)
spring.application.name=springcloud10-Eureka-ribbon-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#配置tomcat的服务的端口号
server.port=8082

consumer的核心配置文件

#指明服务的名称(唯一性)
spring.application.name=springcloud12-Eureka-ribbon-consumer
#指明eureka的服务注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#指明tomcat的服务端口号
server.port=8080
ribbon:
    ConnectTimeout: 3000
    ReadTimeout: 3000
    MaxAutoRetries: 1
    MaxAutoRetriesNextServer: 2
    OkToRetryOnAllOperations: true
    restclient:
        enabled: true

controller

package com.wang.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/test")
    public String test(){
        //RestTemplate restTemplate = new RestTemplate();
        /*
        * 通过注册中心发现服务并访问服务器,其中SPRINGCLOUD03-EUREKA-PROVIDER就是在注册中心的名称(不区分大小写)
        * springcloud会跟根据这个服务名到注册中心获取服务所对应的服务所在IP+端口号,然后利用ResTemlate访问服务
        * */
        ResponseEntity<String> result = restTemplate.getForEntity("http://SPRINGCLOUD10-EUREKA-RIBBON-PROVIDER/test", String.class);
        //  [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20", Date:"Wed, 20 Oct 2021 01:47:43 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }
}

conf

package com.wang.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
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
public class RestTemplateConfig {

    /*
    * 在spring的应用上下文中定义一个Rest模板对象
    * @LoadBalanced 注解用于标记当前的RestTemplate使用Ribbon的负载均衡访问服务的提供者
    * 当使用了Eureka注册中心后必须使用这个注解否则无法正常获取服务,默认情况Ribbon的负载均衡的策略是
    * 轮询的
    * */
    @Bean
    @LoadBalanced
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }

    /**
     * 定义ribbon负载均衡的bean配置,用于改变ribbon的默认负载均衡策略
     * @return
     */
    @Bean
    public IRule iRule(){
        //创建一个随机的Ribbon的负载均衡策略
        return new RandomRule();
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud12EurekaRibbonConsumerApplication {

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

}

4.4RestTemplate请求

​ 1>Get请求

​ 第一种getForEntity
​ 该方法返回一个ResponseEntity对象,ResponseEntity是spring对http请求响应的封装,包括了几个重要的元素,
​ 比如响应码,contentType,contentLengh,响应消息体等

​ 步骤:

​ [1]创建一个工程,导入,作为服务的提供者,在里面创建一个model类,在controller中定义一个返回值为User的方法
​ [2]再创建一个工程,作为消费者,也在里面创建一个model类为user,在controller类中的方法中调用getForEntity接收
​ 另一个工程传来的信息

​ 第二种getForObject(工作时推荐)

​ 2>Post请求

​ 3>put请求

​ 4>delete请求

provider的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud13-RestTemlate-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>

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

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

</project>

springboot核心配置文件

server.port=8081

controller

package com.wang.springcloud.controller;

import com.wang.springcloud.model.User;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public Object test(){
        User user = new User();
        user.setId(1);
        user.setName("小李");
        user.setAge(18);
        User user1 = new User(2, "小明", 20);
        User user2 = new User(3, "小红", 25);

        List<User> list = new ArrayList<>();
        list.add(user);
        list.add(user1);
        list.add(user2);
        //Spring会将List对象转化为对应的json数组返回
        return list;
    }

    @RequestMapping(value = "/test03")
    public Object test03(User user){
        user.setName(user.getName()+"服务提供者");

        //Spring会将List对象转化为对应的json数组返回
        return user;
    }

    @RequestMapping(value = "/getForObjectTest")
    public Object getForObjectTest(){
        User user = new User(5, "赵六", 33);
        return user;
    }

    @RequestMapping(value = "/postTest")
    public Object postTest(User user){
        user.setName(user.getName()+"服务提供者");
        return user;
    }

    @PutMapping(value = "/put")
    public Object put(User user){
        Integer id = user.getId();
        String name = user.getName();
        Integer age = user.getAge();

        System.out.println("name为:"+name+"id为:"+id+"age为:"+age);
        return user;
    }

    @DeleteMapping(value = "/delete")
    public Object delete(Integer id){
        System.out.println(id);
        return "删除成功!";
    }
}

main

package com.wang.springcloud;

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

import java.util.Scanner;

@SpringBootApplication
public class Springcloud13RestTemlateProviderApplication {

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

}

consumer的pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud14-RestTemplate-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>

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

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

</project>

controller

package com.wang.springcloud.controller;

import com.wang.springcloud.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class Mycontroller {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/test")
    public Object test(){
        /**
         * 以get方式提交请求
         * 参数2决定本次响应的结果转化为什么样的类型的数据,如果服务提供者返回的数据是一个符合json对象
         * 的数据,那么参数2可以指定一个实体类或Map集合,用于将这个json数据转化为对应的数据类型
         * 注意:如果服务提供者返回的数据符合json对象格式,那么spring就会将这个数据转化成参数2所指定的数据类型
         */
        ResponseEntity<User> result = restTemplate.getForEntity("http://localhost:8081/test", User.class);
        User user = result.getBody();
        return "consumer从provider处获得的信息为"+user;
    }

    @RequestMapping(value = "/test02")
    public Object test02(){
        /**
         * 如果服务提供者返回的是一个json数组,那么我们消费应该使用一个list集合接收数据,但是集合中的数据类型无论是
         * 什么数据类型,spring都不会自动进行转换,getForEntity方法返回的集合中的数据全部都是map集合(LinkedHashMap集合)
         */
        ResponseEntity<List> result = restTemplate.getForEntity("http://localhost:8081/test", List.class);
        List user = result.getBody();
        return "consumer从provider处获得的信息为"+user;
    }

    @RequestMapping(value = "/test03")
    public Object test03(){
        /**
         * 请求路径中的{0}和{1}和{2}表示请求地址路径中的占位符
         * 需要后期为这些占位符动态的进行赋值
         * 参数3 params 表示请求地址路径中的动态参数作用是为占位符号进行赋值,类型为可变长度的Object类型
         * 注意:
         *     1.占位符中的0和1和2分别对应参数3param数组中的索引值,用于通知Spring数组中指定索引位置中的数据
         *       设置到对应的占位符中
         *     2.这种传传递必须知道参数数字中的每一个元素的类型和含义,因此非常容易出现错误,参数过多时不推荐使用
         */
        String url="http://localhost:8081/test03?id={0}&name={1}&age={2}";
        Object[] obj={3,"李四",21};
        ResponseEntity<User> result = restTemplate.getForEntity( url, User.class, obj);
        User user = result.getBody();
        return "consumer从provider处获得的信息为"+user;
    }

    @RequestMapping(value = "/test04")
    public Object test04(){
        /**
         * 请求路径中的{id}和{name}和{age}表示请求地址路径中的占位符
         * 需要后期为这些占位符动态进行赋值
         * 参数3 params 表示请求地址路径中的动态参数作用是为占位符号进行赋值,类型为Mpa类型
         * 注意:
         *  1.占位符中的id和name和age,对应参数3 param 这个map集合中的key,Spring就会将这个key所
         *    对应的数据设置到指定的占位符中
         *  2.即使map中的value和实际要求的参数类型不一致也不会出错
         *  3.由于SpringMVC中可以直接使用Map集合作为控制器的形参来接收请求中的数据,因此我们不需要
         *    特意定义一个Map集合来作为访问服务提供者的参数对象
         *  4.使用时一定要注意map集合中的每一个key 的名字否者容易出现传值错误,如果访问服务提供者需要
         *    传递多个参数建议使用map集合
         *  5.地址路径占位符不仅可以出现在请求的路径的参数中,也可以出现在请求路径中的任意一个路径域名的位置
         *    如:http://{damain}:{port}/{requestpath}    只不过一般不这么用
         */
        String url="http://localhost:8081/test03?id={id}&name={name}&age={age}";
        Map<String,Object> map = new HashMap<>();
        map.put("id","40");//原本应应该int类型的,但是在map中即使输入string类型,也会转化为int类型
        map.put("name","王五");
        map.put("age",23);
        ResponseEntity<User> result = restTemplate.getForEntity( url, User.class, map);
        User user = result.getBody();
        return "consumer从provider处获得的信息为"+user;
    }

    @RequestMapping(value = "/getForObjectTest")
    public Object testForObjectTest(){
        /**
         * getForObject方法与getForEntity方法的使用方式完全相同,都是对应的后台GepMapping或RequestMapping
         * 区别在于getForOBject是直接将服务提供者返回的数据以参数2所指定的类型返回,不会返回ResponseEntity对象
         * 如果不需要获取服务提供者的响应头信息以及响应编码信息,那么完全可以使用getFouObject来代替getForEntity
         */
        User user = restTemplate.getForObject("http://localhost:8081/getForObjectTest", User.class);
        return "从服务提供者处获得的信息为:"+user;
    }

    @RequestMapping(value = "/postTest")
    public Object postTest(){
        /**
         * Post相关方法
         * 参数1:为请求的地址路径
         * 参数2:为请求的具体参数对象,如果没有参数可以写null
         * 参数3:为本次响应的具体数据类型
         * 参数4:为本次请求的地址路径动态数据,取值为可变的动态长度的Object类型数据或Map集合数据类型,和get相关方法一样
         *
         * 注意:
         *    1.参数2为本次 请求的具体参数数据,参数数据类型为Object类型,但是不能随意传传递一个类型
         *      参数的取值具体为一个Map集合,如果是一个普通的Map集合那么value必须是一个List类型
         *    2.post提交请求的速度相对要慢于get方法,因此在非必要情况下减一使用get请求
         */
        String url="http://localhost:8081/postTest";
        LinkedMultiValueMap params = new LinkedMultiValueMap();
        params.add("name","老李");
        params.add("id","6");
        params.add("age",25);
        User user = restTemplate.postForObject(url, params, User.class);

        return "服务消费者"+user;
    }

    @RequestMapping(value = "/put")
    public Object put(){
        String url="http://localhost:8081/put";
        LinkedMultiValueMap params = new LinkedMultiValueMap();
        params.add("name","张飞");
        params.add("id",7);
        params.add("age",35);
        restTemplate.put(url,params);

        return "消费之执行了put方法";
    }

    @RequestMapping(value = "/delete")
    public Object delete(){
        /**
         * delete方法以get方式提交请求,对应服务提供者的DeleteMapping,用于数据的删除
         * 参数1 为具体的请求路径
         * 参数2 为地址路径的动态参数
         * 注意
         *  delete方法针对于数据的删除,无法获取响应的结果,非必要情况下不建议使用
         *
         */
        String url="http://localhost:8081/delete?id={0}";
        restTemplate.delete(url,8);
        return "删除成功!";
    }
}

conf

package com.wang.springcloud.conf;

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

@Configuration
public class GetRestTem {

    @Bean
    public RestTemplate get(){
        return new RestTemplate();
    }
}

main

package com.wang.springcloud;

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

@SpringBootApplication
public class Springcloud14RestTemplateConsumerApplication {

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

}

5.服务的熔断Hystrix

5.1介绍

​ 开发中可能会遇到的情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n9gFDW3C-1635942021547)(https://raw.githubusercontent.com/OneTimes1/photo/master/C:%5CUser%5C14330%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images202111032012865.png)]

​ 熔断器也叫断路器,他们表示同一个意思."熔断器"本身是一种开关装置,用于在电路上保护先线路过载,当线路中有电器发 生短路时,能够及时切断故障电路,防止发生过载,发热甚至起火等严重后果

​ 在微服务架构中的熔断器,就是当被调用方网友响应,调用方直接返回一个错误响应即可, 而不是漫长的等待,这样避免调用 时因为等待线程而一直得不到释放,避免故障在分布式的系统见蔓延

​ Hystrix 的目的是在于对延迟和故障提供更强大的容错能力 . Hystrix具备服务降级,服务熔断,线程和信号隔离,请求缓存,
​ 请求合并以及服务监控等强大的功能

image-20211027211712272

5.2Hystrix使用

​ Hystrix是在服务的消费者中使用的

​ [1]创建一个consumer工程,依赖为springcloud,Eureka client,以及SpringCloud Circuit Breaker 中的Hystrix
​ [2]创建一个provider工程,创建一个controller类,在注册中心中注册自己的服务
​ [3]创建一个Eureka 注册中心的server工程
​ [4]在消费者的main加上注解 , 激活熔断器
​ [5]消费者的controller的方法上加注解,在里面加入参数,如果抛异常就会调用该注解指定的方法
​ [6]在消费者的当前的controller 的类中定义一个方法,作为熔断处理
​ [7]修改服务提供者的方法,模拟服务出错

​ 注:可能会出现的问题熔断机制的注解无法使用,由于springboot和springcloud的版本太高,需要添加熔断器的启动
​ 依赖,具体可以参考(31条消息) java.lang.IllegalStateException: Annotation @EnableCircuitBreaker found, but there are no implementa_jj89929665的博客-CSDN博客
​ 将依赖与这篇博客中的内容保持一致即可

​ 服务延迟:
​ [8]在服务提供者中在创建一个方法,模拟服务延迟
​ 在服务消费者中调用该方法,配置熔断注解和熔断器时间

​ 服务降级:
​ [9]在consumer中创建一个方法,在provider中也创建一个方法,
​ provier中抛空指针异常
​ 在consumer的error方法中传入一个类型为Throwable的参数,在该方法内获取其类型

​ 忽略异常:
​ [10]在consumer工程的controller中创建一个方法,在其注解上指明要忽略的异常
​ 在provider工程的controller中创建一个方法,抛出一个异常
​ [11]启动服务,并访问consumer中的方法,发现控制台打印出异常信息,即该异常没有被熔断,而是被忽略掉了

​ 自定义熔断器类:
​ [12]在consumer中创建一个类,继承HystrixCommand,实现其方法构造器方法和run方法
​ 这个类就是要自定义的熔断器类
​ 两个属性: RestTemplate , string
​ 在该类中定义三个方法:
​ 有参构造的方法(因为其父类没有无参构造),在构造方法中给两个属性赋值
​ 重写run方法: 当访问其provider中的服务时,spring会自动调用该方法
​ 从写getFallback方法: 当spring调用privoder中的服务出错时,会调用该方法
​ 在consumer的controller中创建一个方法调用provider中的方法
​ 在provider中创建一个抛出异常的方法

​ 自定义熔断器类和异常处理的区别就是自定义熔断处理无法处理超时的异常

5.3Hystrix仪表盘

​ 作用: 监控hystrix的熔断详情,可以记录hystrix的熔断次数
​ 其使用时必须依赖springboot的健康检查机制功能

​ 使用:
​ [1]创建一个springboot工程
​ 导入仪表盘的依赖
​ 将其端口号改为9000
​ [2]在main方法上加上注解,激活仪表盘功能
​ [3]在一个使用了hystrix的consumer工程的pom文件中添加springboot的服务监控的依赖
​ 配置该consumer工程的springboot核心配置文件,指定springboot的健康检查机制要监控的方法

eureka-server工程

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud15HystrixEurekaServerApplication {

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

}

springboot核心配置文件

server.port=9100
eureka.instance.hostname=loaclhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:9100/eureka

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud15-hystrix-eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

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

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

</project>

eureka-provider工程

package com.wang.springclooud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud16HystrixEurekaProviderApplication {

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

}

controller

package com.wang.springclooud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyConreoller {

    @RequestMapping("/test")
    public String test(){
        //模拟服务提供者出现错误
        System.out.println(10/0);
        return "这是服务提供者的正常方法";
    }

    @RequestMapping("/test02")
    public String test02(){
        //模拟服务提供者出现延迟
        try {
            Thread.sleep(16000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "这是服务提供者的正常方法";
    }

    @RequestMapping("/test03")
    public String test03(){
        //模拟服务提供者出现异常
        System.out.println(10/0);
        return "这是服务提供者的正常方法";
    }

    @RequestMapping("/test05")
    public String test05(){
        //模拟服务提供者出现异常
        System.out.println(10/0);
        return "这是服务提供者的正常方法";
    }
}

springboot的核心配置文件

#指名服务的名称(唯一性)
spring.application.name=springcloud16-hystrix-eureka-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#配置tomcat的服务的端口号
server.port=8081

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springclooud</groupId>
    <artifactId>springcloud16-hystrix-eureka-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

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

</project>

eureka-consumer工程

package com.wang.springcloud;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;

import java.util.Arrays;

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class Springcloud17HystrixEurekaConsumerApplication {

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

    @Bean
    public ServletRegistrationBean getServlet(){
        HystrixMetricsStreamServlet hystrixMetricsStreamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(hystrixMetricsStreamServlet);

        servletRegistrationBean.setLoadOnStartup(1);
        servletRegistrationBean.setUrlMappings(Arrays.asList("/hystrix.stream"));
        servletRegistrationBean.setName("HystrixMetricsStreamServlet");
        return servletRegistrationBean;
    }

}

RestTemplateConfig

package com.wang.springcloud.conf;

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
public class RestTemplateConfig {

    /*
    * 在spring的应用上下文中定义一个Rest模板对象
    * @LoadBalanced 注解用于标记当前的RestTemplate使用Ribbon的负载均衡访问服务的提供者
    * 当使用了Eureka注册中心后必须使用这个注解否则无法正常获取服务,默认情况Ribbon的负载均衡的策略是
    * 轮询的
    * */
    @Bean
    @LoadBalanced
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }

}

cuontroller

package com.wang.springcloud.controller;

import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.wang.springcloud.hystrix.MyHystrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {
    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "error")
    @RequestMapping(value = "/test")
    public String test(){

        ResponseEntity<String> result = restTemplate.getForEntity("http://springcloud16-hystrix-eureka-provider/test", String.class);
        //  [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20", Date:"Wed, 20 Oct 2021 01:47:43 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }

    /**
     * 属性:
     *  commandProperties用于设置熔断器的一些属性
     *      @HystrixProperty 注解用于指定一个熔断的属性
     *          execution.isolation.thread.timeoutInMilliseconds 表示熔断的超时时间,如果服务在指定的时间内
     *          没有返回,则表示超时需要熔断,默认为1000毫秒
     *          value 用于指定属性的值,1500表示1.5秒,用于自定义熔断器的超时时间
     */
    @HystrixCommand(fallbackMethod = "error",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")
    })
    @RequestMapping(value = "/test02")
    public String test02(){

        ResponseEntity<String> result = restTemplate.getForEntity("http://springcloud16-hystrix-eureka-provider/test02", String.class);
        //  [Content-Type:"text/plain;charset=UTF-8", Content-Length:"20", Date:"Wed, 20 Oct 2021 01:47:43 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }

    @HystrixCommand(fallbackMethod = "error")
    @RequestMapping(value = "/test03")
    public String test03(){

        ResponseEntity<String> result = restTemplate.getForEntity("http://springcloud16-hystrix-eureka-provider/test03", String.class);
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }

    /**
     * 参数:  ignoreExceptions就是要忽略的异常,如果程序出现了指定的异常后将不再进行熔断,而是将错误直接抛出,
     *       抛给服务的调用者,这个调用者可能是用户也可能是其它服务
     */
    @HystrixCommand(fallbackMethod = "error",
            ignoreExceptions = {HttpServerErrorException.InternalServerError.class}
    )
    @RequestMapping(value = "/test04")
    public String test04(){

        ResponseEntity<String> result = restTemplate.getForEntity("http://springcloud16-hystrix-eureka-provider/test04", String.class);
        String body = result.getBody();//获取响应的结果
        return "使用了Eureka服务的消费者------------"+body;
    }

    @RequestMapping(value = "/test05")
    public String test05(){
        String url="http://springcloud16-hystrix-eureka-provider/test05";

        MyHystrix myHystrix = new MyHystrix(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("")),restTemplate,url);
        //执行请求并获取响应结果
        //execute方法后台会自动调用run方法访问服务的提供者,如果服务提供者抛出异常则自动调用getFallback方法返回响应的数据
        String body = myHystrix.execute();

        return "使用了Eureka服务的消费者------------"+body;
    }

    /**
     * 服务的降级方法,当我们的某个控制器方法被熔断以后就不能放回给客户一个响应结果,因此在服务熔断藏会自动调用这个
     * 服务的降级方法,来为用户返回一个本地的响应信息,这个信息虽然不是真正的处理结果,但是至少我们可以返回育一个友好
     * 的提示,避免用户看见错位内容的还无限等待
     *
     * 参数1 Throwable只要被监控的控制方法出现异常,就会自动熔断,无论是控制本身还是远程服务出现异常,
     *       参数Throwable都会被spring注入一个异常对象
     *  注意: 如果是服务提供者抛出异常,那么spring会注入一个Springcloud17HystrixEurekaConsumerApplication
     *        异常对象, 获取的异常并不是我们服务提供者实际出现的异常
     */
    public String error(Throwable throwable){

        System.out.println(throwable.getClass());
        System.out.println(throwable.getMessage());

        return "启动熔断机制";
    }
}

MyHystrix

package com.wang.springcloud.hystrix;

import com.netflix.hystrix.HystrixCommand;
import org.springframework.web.client.RestTemplate;

public class MyHystrix extends HystrixCommand<String> {

    private RestTemplate restTemplate;
    private String url;

    /**
     * 自定义一个有参的构造方法,由于父类没有无参构造方法,所以子类必须有有参构造方法
     * @param setter
     * @param restTemplate
     * @param url
     */
    public MyHystrix(Setter setter, RestTemplate restTemplate,String url) {
        super(setter);
        this.restTemplate = restTemplate;
        this.url=url;
    }

    /**
     * 这个方法不能手动调用,spring会自动调用这个方法来访问我们的服务提供者
     * @return
     * @throws Exception
     */
    @Override
    protected String run() throws Exception {
        return restTemplate.getForObject(url,String.class);
    }

    @Override
    protected String getFallback() {
        System.out.println(super.getFailedExecutionException().getClass());
        System.out.println(super.getFailedExecutionException().getMessage());

        return "自定义服务熔断";
    }
}

springboot的核心配置文件

#指明服务的名称(唯一性)
spring.application.name=springcloud17-hystrix-eureka-consumer
#指明eureka的服务注册中心
eureka.client.service-url.defaultZone=http://eureka9100:9100/eureka
#指明tomcat的服务端口号
server.port=8080
#指定那些服务需要用springboot的健康检查机制监控
management.endpoints.web.exposure.include=*

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud17-hystrix-eureka-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

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

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

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

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

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

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

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

</project>

hystrix-dashbord仪表盘工程

package com.wang.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.Bean;

import java.util.Arrays;

@SpringBootApplication
//开启仪表盘的注解
@EnableHystrixDashboard
public class Springcloud18HystrixDashbordApplication {

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


}

springboot的核心配置文件

server.port=9000
hystrix:
    dashboard:
        proxy-stream-allow-list: localhost

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud18-hystrix-dashbord</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

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

</project>

6.Feign

6.1Feign是什么

​ Feign是Netfix公司开发的一个声明式的REST调用客户端

​ Ribbon负载均衡和Hystrix服务熔断在开发中是常用的,但是每次写的代码都差不多,所以就有了feign.
​ feign是整合了ribbon和hystrix两大组件,就好像springboot整合了spring和springmvc一样,使其使用时变得
​ 简单

image-20211102095858510

6.2使用Feign

​ 步骤:

​ [1]创建一个工程,作为server
​ 创建一个工程,作为服务的provider
​ 创建一个工程,作为服务的consumer
​ [2]在provider工程中创建一个方法作为服务的提供者,并配置该工程的端口号和springboot核心配置文件,在main上加 注解
​ 在consumer工程中创建一个方法作为服务的远程调用者, 并配置该工程的端口号和springboot核心配置文件,在main 上加注解
​ 在server工程中的main方法上加注解,配置其springboot的核心配置文件
​ [3]consumer中的两个依赖
​ main方法上加注解,激活feign
​ 创建一个接口,类上面加上feign的注解,在里面定义一个方法, 该方法上面加注解@requestMapping(value=“服务提供 者的服务名”) , 该方法的返回值类型为服务提供者的返回值
​ [4]在consumer的controller的方法中加引用该接口,通过spring的注解自动注入对象 , 并调用该接口中的方法

​ 服务中带有参数:
​ [5]在provider的controller类中创建一个方法,在该方法中传递两个参数
​ 在consumer的接口类中创建一个方法,该方法传入的参数类型和provider中新建的方法参数类型一致,并在参数前加
​ @RequestParam注解
​ 在consumer的controller类中创建一个方法,并调用接口中的方法,传入两个参数

​ 服务中带有的参数类型为对象型:
​ [6]和[5]中的步骤几乎一样,只是传入的参数类型为对象型的,这就需要分别在服务提供者和消费者中创建一个user对象,
​ 并且需要在consumer的接口中的参数对象前和provider接收对象的方法参数前 加@Requestbody注解

​ consumer从后台获取一个实体对象
​ [7]在provider的方法中创建一个返回值类型为user的方法,在接口类中调用,在controller类中调用该接口类中的方法

​ consumer从后台获取多个实体对象List集合
​ [8]在provider中创建一个方法,该方法的返回结果是一个List的集合
​ 在consumer的接口类中接收该数据,该方法的返回类型也为List集合
​ 在consumer的controller类中的创建一个方法,调用接口中的方法,将接口返回的List集合展现在前端

​ 使用熔断器
​ [9]在provider中创建一个方法,抛出异常
​ 在consumer中的自定义接口中创建一个方法,调用服务提供者中的方法
​ 在consumer的controller中创建一个方法调用接口中的抛异常的方法
​ 在consumer中创建一个类,实现自定义的接口,重写接口中的每个方法,在每个方法中定义熔断的内容,并在该类的上 面加上一个@Component注解
​ 在consumer中的自定义接口的上面加上熔断处理
​ 在consumer的springboot核心配置文件中开启feign的熔断处理
​ 注: 新版springcloud中的feign中的回退方式和旧版的不太一样,新版中在springboot中开启人熔断的配置为
​ feign.circuitbreaker.enabled=true
​ 老版为 feign.hystrix.enabled=true

​ 使用可获取异常信息的熔断器类
​ [10]在comsumer中创建一个类,继承FallbackFactory<>,泛型为自定义的接口类
​ 在该类中return 时new 一个HelloService,使用匿名内部类的方式返回熔断处理的结果
​ 在自定义的接口中上面的注解中写fallbackFactory定义自定义熔断器类

frign-server工程:

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud19FrignServerApplication {

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

}
server.port=9100
eureka.instance.hostname=loaclhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:9100/eureka

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud19-frign-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

frign-provider工程

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud20FrignProviderApplication {

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

}

controller

package com.wang.springcloud.controller;

import com.wang.springcloud.model.User;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public String test(){
        return "这是一个frign下的8081服务提供者";
    }

    @RequestMapping(value = "/paramTest")
    public String paramTest(String name,Integer age){
        return "用户的name为:"+name+"用户的年龄为:"+age;
    }

    /**
     * 如果访问服务提供者时需要使用对象类型转化数据,那么必须为这个参数添加一个@RequestBody注解,
     *  否者参数无法传递到服务提供者中,如果服务提供者也是使用对象来接收请求的参数,那么服务提供者的参数也
     *  必须加@resquestBody注解
     */
    @RequestMapping(value = "/paramTest02")
    public String paramTest02(@RequestBody User user){
        return "用户的name为:"+user.getName()+"用户的年龄为:"+user.getAge();
    }

    /**
     * 如果服务提供者返回的Json数据符合Json对象的格式,那么我们就可以使用一个实体类或一个Map集合响应数据
     */
    @RequestMapping(value = "/paramTest03")
    public Object paramTest03(){
        User user = new User();
        user.setName("张飞");
        user.setAge(23);
        return user;
    }

    @RequestMapping(value = "/paramTest04")
    public List<User> paramTest04(){
        User user1 = new User("关羽", 35);
        User user2 = new User("刘备", 34);
        List<User> list=new ArrayList<>();
        list.add(user1);
        list.add(user2);
        return list;
    }

    @RequestMapping(value = "/paramTest05")
    public String paramTest05(){
        System.out.println(10/0);
        return "这是熔断异常方法";
    }
}

user

package com.wang.springcloud.model;

public class User {
    private String name;
    private Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

application

#指名服务的名称(唯一性)
spring.application.name=springcloud20-frign-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#配置tomcat的服务的端口号
server.port=8081

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud20-frign-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

frign-consumer工程

package com.wang.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class Springcloud21FrignConsumerApplication {

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

}

controller

package com.wang.springcloud.controller;

import com.wang.springcloud.inter.HelloService;
import com.wang.springcloud.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
public class MyController {

    @Resource
    private HelloService helloService;

    @RequestMapping(value = "test01")
    public String test01(){
        String body = helloService.test();
        return "这是consumer服务消费者:"+body;
    }

    @RequestMapping(value = "paramTest")
    public String paramTest(){
        String body = helloService.paramTest("张三",18);
        return "这是consumer服务消费者:"+body;
    }

    @RequestMapping(value = "paramTest02")
    public String paramTest02(User user){
        String body = helloService.paramTest02(user);
        return "consumer服务消费者:"+body;
    }

    @RequestMapping(value = "/paramTest03")
    public String parmaTest03(Integer id){
        User user = helloService.paramTest03();
        return "id为:"+id+"的用户的姓名为:"+user.getName()+"年龄为:"+user.getAge();
    }

    @RequestMapping(value = "/paramTest04")
    public String paramTest04(){
        List<User> users = helloService.paramTest04();
        for (User user: users) {
            System.out.println("姓名为:"+user.getName()+"年龄为:"+user.getAge());
        }
        return "所有的用户的信息为----"+users;
    }

    @RequestMapping(value = "/paramTest05")
    public String paramTest05(){
        String body = helloService.paramTest05();
        return "熔断没有触发,程序正常执行----"+body;
    }
}

MyFallbackFactory

package com.wang.springcloud.hystrix;

import com.wang.springcloud.inter.HelloService;
import com.wang.springcloud.model.User;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class MyFallbackFactory implements FallbackFactory<HelloService> {
    /**
     * 通过匿名内部类的方式处理熔断
     * 可以通过cause获取异常信息
     */
    @Override
    public HelloService create(Throwable cause) {
        return new HelloService() {
            @Override
            public String test() {
                return null;
            }

            @Override
            public String paramTest(String name, Integer age) {
                return null;
            }

            @Override
            public String paramTest02(User user) {
                return null;
            }

            @Override
            public User paramTest03() {
                return null;
            }

            @Override
            public List<User> paramTest04() {
                return null;
            }

            @Override
            public String paramTest05() {
                System.out.println(cause.getCause());
                System.out.println(cause.getMessage());
                return "启用熔断处理机制";
            }
        };
    }
}

Myhystrix

package com.wang.springcloud.hystrix;

import com.wang.springcloud.inter.HelloService;
import com.wang.springcloud.model.User;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class Myhystrix implements HelloService {
    @Override
    public String test() {
        return "test启动熔断异常处理";
    }

    @Override
    public String paramTest(String name, Integer age) {
        return "paramTest启动熔断异常处理";
    }

    @Override
    public String paramTest02(User user) {
        return "paramTest02启动熔断异常处理";
    }

    @Override
    public User paramTest03() {
        return null;
    }

    @Override
    public List<User> paramTest04() {
        return null;
    }

    @Override
    public String paramTest05() {
        return "paramTest05启动熔断异常处理";
    }
}

HelloService接口

package com.wang.springcloud.inter;

import com.wang.springcloud.hystrix.MyFallbackFactory;
import com.wang.springcloud.hystrix.Myhystrix;
import com.wang.springcloud.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

/**
 * @FeignClient 用于标记当前接口是一个Feign的声明式服务接口
 * spring会为这个接口生成动态代理对象
 * 属性
 *   name 用于指定注册中心中的某个服务的名字
 *   fallback 指定一个自定义的异常熔断类,当使用生命式接口中的方法调用远程服务时
 *   如果服务出现了异常,则自动执行fallback所指定的这个类中的对应的方法来执行服务的降级
 *   fallbackFactory 指定一个自定义的异常熔断器类,这个熔断器类剋以获取异常信息
 */
@FeignClient(name = "springcloud20-frign-provider",fallback = Myhystrix.class)
public interface HelloService {

    //RequestMapping 这里用于只当我们需要访问的服务提供者的请求路径
    @RequestMapping(value = "/test")
    public String test();

    @RequestMapping(value = "/paramTest")
    public String paramTest(@RequestParam String name,@RequestParam Integer age);

    @RequestMapping(value = "/paramTest02")
    public String paramTest02(@RequestBody User user);

    @RequestMapping(value = "/paramTest03")
    public User paramTest03();

    @RequestMapping(value = "/paramTest04")
    public List<User> paramTest04();

    @RequestMapping(value = "/paramTest05")
    public String paramTest05();


}

springboot核心配置文件

#指明服务的名称(唯一性)
spring.application.name=springcloud21-frign-consumer
#指明eureka的服务注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#指明tomcat的服务端口号
server.port=8080
#开启feign的熔断处理
feign.circuitbreaker.enabled=true

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud21-frign-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

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

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

</project>

7.API网关Zuul

7.1介绍

​ 1>什么是Zuul?

​ Zuul 是一个 API 网关的具体实现,API 网关是对外提供服务的一个入口,并且隐藏了内部架构的实现,是微服务架 构中必不可少的一个组件。API 网关可以为我们管理大量的 API 接口,负责对接客户、协议适配、安全认证、路由转 发、流量限制、日志监控、防止爬虫、灰度发布等功能

​ 2>为什么需要Zuul

​ [1]Zuul、Ribbon、Eureka 三个组件相结合,可以实现动态路由和负载均衡的功能,Zuul 能够将请求流量按某种策略 分发到集群中的多个服务实例
​ [2] 网关是将所有服务的API接口统一聚合,并统一对外暴漏,外界系统调用API接口时,都是由网关对外暴露的 API 接 口,外界系统不需要知道微服务系统中个服务互相调用的复杂性。同时也保护了其内部微服务单个的 API 接口,防 止其被外界直接调用,导致服务的敏感信息对外暴露。
​ [3]网关可以做用户的身份认证和权限认证,防止非法请求操作API接口,对服务器起保护作用
​ [4]网关可以用来实现流量监控,在高流量的情况下,对服务进行降级

​ 3>应用场景

​ [1]动态路由

image-20211102105424551

image-20211102105512300

​ [2]认证鉴定

image-20211102105718571

7.2使用

​ [1]创建三个工程,一个作为注册中心,一个作为服务的provider,一个作为服务的consumer
​ [2]创建一个工程,作为zull网关
​ 依赖: zull起步依赖
​ 在main方法上加注解,激活zull
​ 在springboot的核心配置文件中配置zull的拦截路径
​ [3]在consumer的controller中创建一个方法
​ 访问网关服务中配置的地址
​ [4]在浏览器端访问该方法

​ ❤️注:可能遇到的问题:idea报错java.lang.NoSuchMethodError: org.springframework.boot.web.servlet.error.ErrorController.getErrorPath()Ljava/lang/String;
​ 这其实是因为idea和springboot以及springcloud的版本不兼容所导致的
​ 高版本的springcloud是不支持zuul的,需要更换低版本的

​ 使用zuul进行请求过滤
​ [5]在zull网关工程中创建一个方法,其方法继承的是ZuulFilter类,在该类的上面加上一个@Component注解
​ 重写其父类中的方法,设置拦截规则
​ [6]修改consumer中controller中的一个方法,在其请求路径后面加上token作为拦截判断

​ [7]再创建一个和[5]中一样的方法, 修改其 执行的优先级,
​ 然后启动服务,客户端访问,拦截器会依次执行

​ 忽略路由:
​ [8]在zuul网关工程中的springboot的核心配置文件中设置要忽略的路径
​ 一旦设置,那么在通过网关访问这些路径的时候,就会报404找不到页面

​ 网关的自我转发:
​ [9]在zuul网关工程中的springboot的核心配置文件中加自我转发的路径
​ 在zuul网关工程中创建一个controller类,在里面定义一个方法,作为自我转发
​ 注:如果不配置,那么是无法在zuul网关工程中访问的,只有配置好了,才能访问

​ 异常拦截:防止过滤器出现异常导致用户的浏览器页面出现错误的信息
​ [10]在zuul工程的springboot和核心配置文件中配置禁用默认的异常配置
​ 创建一个异常过滤器的处理类,也是继承的是ZuulFilter类:
​ 其filterType方法返回是eorror
​ 在run方法中声明抛出的异常的处理方法,返回给用户页面信息

​ 自定义异常error页面(和上面的[10]二选一即可)
​ [11]在zuul工程中开启使用zuul的默认处理异常
​ 在zuul工程中的controller下创建一个类实现ErrorController接口
​ 在这个类中getErrorPath的返回结果为error,将[10]中的方法shouldFilter改为false禁用
​ 再定义一个方法,在方法的上面加@RequestMapping(value = “/error”)注解
​ 在这个类的上面加@controller注解

​ 补充:路由规则通配符的含义:
image-20211102202041757

zuul-server

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud22-eureka-zuul-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

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

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

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

</project>

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaServer
public class Springcloud22EurekaZuulServerApplication {

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

}

springboot核心配置文件

server.port=9100
eureka.instance.hostname=eureka9100
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:9100/eureka

zuul-provider

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud23EurekaZuulProviderApplication {

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

}

controller

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @RequestMapping(value = "/test")
    public String test(){
        return "这是一个zuul的服务提供者";
    }

    @RequestMapping(value = "/test02")
    public String test02(){
        return "这是一个zuul的服务提供者test02";
    }
}

springboot核心配置文件

#指名服务的名称(唯一性)
spring.application.name=springcloud23-eureka-zuul-provider
#指明eureka服务的注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#配置tomcat的服务的端口号
server.port=8081

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud23-eureka-zuul-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud23-eureka-zuul-provider</name>
    <description>springcloud23-eureka-zuul-provider</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

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

</project>

zuul-consumer

main

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
public class Springcloud24EurekaZuulConsumerApplication {

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

}

config

package com.wang.springcloud.conf;

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
public class RestTemplateConfig {

    /*
    * 在spring的应用上下文中定义一个Rest模板对象
    * @LoadBalanced 注解用于标记当前的RestTemplate使用Ribbon的负载均衡访问服务的提供者
    * 当使用了Eureka注册中心后必须使用这个注解否则无法正常获取服务,默认情况Ribbon的负载均衡的策略是
    * 轮询的
    * */
    @Bean
    @LoadBalanced
    public RestTemplate getrestTemplate(){
        return new RestTemplate();
    }
}

controller

package com.wang.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {

    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/test")
    public String test(){
        String body = restTemplate.getForObject("http://springcloud23-eureka-zuul-provider/test", String.class);
        return "未使用zuul网关过滤的消费者------------"+body;
    }

    @RequestMapping(value = "/test02")
    public String test02(String token){
        String url="http://SPRINGCLOUD25-EUREKA-ZUUL-GETWAY/api-zuul/test?token="+token;
        String body = restTemplate.getForObject(url,String.class);
        return "使用了zuul网关过滤的的消费者------------"+body;
    }
}

springboot核心配文件

#指明服务的名称(唯一性)
spring.application.name=springcloud24-eureka-zuul-consumer
#指明eureka的服务注册中心
eureka.client.service-url.defaultZone=http://localhost:9100/eureka
#指明tomcat的服务端口号
server.port=8080

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud24-eureka-zuul-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud24-eureka-zuul-consumer</name>
    <description>springcloud24-eureka-zuul-consumer</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

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

</project>

zuul-getway

package com.wang.springcloud;

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

@SpringBootApplication
@EnableEurekaClient
//激活zuul代理
@EnableZuulProxy
public class Springcloud25EurekaZuulGetwayApplication {

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

}

controller

package com.wang.springcloud.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Mycontroller {

    @RequestMapping(value = "/api/local")
    public String test(){
        return "这是zuul工程下的controller";
    }

}

自定义网关拦截异常处理类

package com.wang.springcloud.controller;

import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyErrorHandler implements ErrorController {
    //当项目中的某个请求出现异常以后,则会执行这个控制器中的这个方法来获取处理异常的请求地址
    //然后自动执行这个请求的显示错位信息
    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping(value = "/error")
    @ResponseBody
    public String error(){
        RequestContext context = RequestContext.getCurrentContext();
        ZuulException exception= (ZuulException) context.getThrowable();

        return "全局错误页面Code:"+exception.nStatusCode+"----message"+exception.getMessage();
    }
}

网关异常处理类(与上面的二选一)

package com.wang.springcloud.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
public class MyErrorFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "error";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        try {
            RequestContext context = RequestContext.getCurrentContext();
            //获取异常对象
            ZuulException exception = (ZuulException) context.getThrowable();
            HttpServletResponse response = context.getResponse();

            response.setStatus(exception.nStatusCode);
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out=null;
            try {
                out=response.getWriter();
                out.println("出现异常了code:"+exception.nStatusCode+" message:"+exception.getMessage());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out!=null){
                    out.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

网关过滤器

package com.wang.springcloud.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

//自定义一个过滤器类用于拦截用户的请求,并继承zuul提供的过滤器类
@Component
public class MyFilter extends ZuulFilter {

    //过滤器类型,决定在请求之前还是在请求之后指定当前过滤器
    @Override
    public String filterType() {
        //返回pre表示在请求之前执行过滤器
        return "pre";
    }

    //过滤器的排序,如果有多个过滤器,那么这些过滤器将按照返回值大小直接排序执行
    @Override
    public int filterOrder() {
        return 0;
    }

    //是否启用当前过滤器,如果返回true,表示启动当前过滤器,返回false表示不启用当前过滤器
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //如果进入当前过滤器后,这个方法就是过滤器中具体的业务逻辑
    //注意:这个返回值目前版本没有特使的作用,因此返回null即可
    @Override
    public Object run() throws ZuulException {
        //模拟网关过滤器出现异常
        System.out.println(10/0);
        //获取当前请求的上下文根
        RequestContext context = RequestContext.getCurrentContext();
        //获取当前请求对象
        HttpServletRequest request = context.getRequest();
        //获取请求中的token参数数据
        String token = request.getParameter("token");
        if (token==null||!"123".equals(token)){
            //通知zullapi网关当前请求非法
            context.setSendZuulResponse(false);
            //设置响应编码401,表示权限不足
            context.setResponseStatusCode(401);
            //设置响应的头文件信息为html或文本响应编码为utf-8
            context.addZuulResponseHeader("content-type","text/html;charset=utf-8");
            //设置响应的内容
            context.setResponseBody("非法访问!");
        }else {
            System.out.println("用户携带了身份令牌,需要验证这个身份是否合法");
        }
        return null;
    }
}

网关过滤器

package com.wang.springcloud.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

//自定义一个过滤器类用于拦截用户的请求,并继承zuul提供的过滤器类
@Component
public class MyFilter02 extends ZuulFilter {

    //过滤器类型,决定在请求之前还是在请求之后指定当前过滤器
    @Override
    public String filterType() {
        //返回pre表示在请求之前执行过滤器
        return "pre";
    }

    //过滤器的排序,如果有多个过滤器,那么这些过滤器将按照返回值大小直接排序执行
    @Override
    public int filterOrder() {
        return 1;
    }

    //是否启用当前过滤器,如果返回true,表示启动当前过滤器,返回false表示不启用当前过滤器
    @Override
    public boolean shouldFilter() {
        return true;
    }

    //如果进入当前过滤器后,这个方法就是过滤器中具体的业务逻辑
    //注意:这个返回值目前版本没有特使的作用,因此返回null即可
    @Override
    public Object run() throws ZuulException {
        //获取当前请求的上下文根
        RequestContext context = RequestContext.getCurrentContext();
        //获取当前请求对象
        HttpServletRequest request = context.getRequest();
        //获取请求中的token参数数据
        String token = request.getParameter("token");
        if (token==null||!"123".equals(token)){
            //通知zullapi网关当前请求非法
            context.setSendZuulResponse(false);
            //设置响应编码401,表示权限不足
            context.setResponseStatusCode(401);
            //设置响应的头文件信息为html或文本响应编码为utf-8
            context.addZuulResponseHeader("content-type","text/html;charset=utf-8");
            //设置响应的内容
            context.setResponseBody("非法访问!");
        }else {
            System.out.println("MyFilter02用户携带了身份令牌,需要验证这个身份是否合法");
        }
        return null;
    }
}

springboot核心配置文件

#配置服务内嵌的Tomcat端口
server.port=9000
#配置服务的名称
spring.application.name=springcloud25-eureka-zuul-getway
#配置API网关到注册中心上,API网关也将作为一个服务注册到eureka-server上
eureka.client.service-url.defaultZone=http://localhost:9100/eureka

#配置路由规则zuul.routes.api-zuul.path 中api-zuul 可以任意填写
#/api-zuul/** 表示请求的拦截规则类似拦截器的拦截规则以/api-zuul开头的任意目录以及子孙目录中所有请求都会被拦截
#zuul.routes.api-zuul.path=/api-zuul/**
#指向服务名字 用于对这个服务下的某个写特定请求进行拦截
#zuul.routes.api-zuul.serviceId=springcloud23-eureka-zuul-provider

#指定拦截路径也有简化写法
zuul.routes.springcloud23-eureka-zuul-provider=/api-zuul/**

#忽略路由
#一旦配置,那么通过网关访问该路径就会报找不到资源404
#zuul.ignored-patterns=/api-zuul/test02

#配置统一网关访问前缀,这个前缀就类似我们之前配置的tomcat的应用上下文根
#zuul.prefix=/myapi

#配置自我转发,将某些请求转发到当前的网关工程中
#当访问的路径为localhost:9000/getway/** 时,就会跳转到当前工程的api/local 中
zuul.routes.getway.path=/getway/**
zuul.routes.getway.url=forward:/api/local

#配置关闭zuul中的默认网关异常处理
#zuul.SendErrorFilter.error.disable=true

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.wang.springcloud</groupId>
    <artifactId>springcloud25-eureka-zuul-getway</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

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

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

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

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.example.demo1.Demo1Application</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值