01.Spring Cloud Feign 远程调用

what:是什么

  • 是RestTemplate的一种优化替代方案
  • 用于发送微服务的请求

why:为什么使用

  • 解决了url硬编码问题
  • 解决了url复用问题

where:在哪里使用

  • 微服务项目中

when:什么时候使用

  • 当想要发送微服务请求的时候

how:如何使用

  • 导入依赖feign的starter
  • 启动引导类加@EnableFeignClients注解
  • 编写FeignClient接口,使用SpringMVC的注解
  • 在Controller中注入Feign接口,直接调用,无需实现类
  • 访问接口测试

在消费者服务中导入依赖feign的starter

<!--配置feign-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

修改消费者服务启动类:启动引导类加@EnableFeignClients注解,Feign中已经自动集成Ribbon负载均衡

package com.lxgzhw;

import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

//注解简化写法:微服务中,注解往往引入多个,简化注解可以使用组合注解。@SpringCloudApplication =等同于@SpringBootApplication+@EnableDiscoveryClient+@EnableCircuitBreaker
@SpringCloudApplication
@EnableFeignClients//开启Feign功能
public class ConsumerServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerServerApplication.class, args);
    }
}

编写FeignClient接口,使用SpringMVC的注解

  • 在consumer_service中编写Feign客户端UserService接口类
package com.lxgzhw.service;

import com.lxgzhw.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("user-service")//指定feign调用的服务
public interface UserService {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Integer id);
}
  • Feign会通过动态代理,帮我们生成实现类。
  • 注解@FeignClient声明Feign的客户端接口,需指明服务名称
  • 接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们逆向生成URL地址然后请求

在Controller中注入UserService接口,直接调用,无需实现类

package com.lxgzhw.controller;

import com.lxgzhw.pojo.User;
import com.lxgzhw.service.UserService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "defaultFallback")//开启默认的FallBack,统一失败降级方法(兜底)
public class ConsumerController {
    @Autowired
    private UserService userService;

    /**
     * 负债均衡+服务熔断的写法
     *
     * @param id 用户id
     * @return 用户对象
     */
    @GetMapping(value = "/{id}", produces = "application/json; charset=UTF-8")
    @HystrixCommand //使用全局默认的降级方法
    public User findById(@PathVariable Integer id) {
        return userService.findById(id);
    }

    /**
     * 默认降级方法,不需要任何参数,但是返回值必须保持一致
     */
    public User defaultFallback() {
        User user = new User();
        user.setNote("默认提示:对不起,网络太拥挤了!");
        return user;
    }
}

启动测试:访问接口http://localhost:8080/consumer/1

02.负载均衡

what:是什么

  • 负载均衡是远程过程调用必备的要素。
  • Feign本身集成了Ribbon,因此不需要额外引入依赖,也不需要再注册RestTemplate对象。即可无感知使用负载均衡这一特性。

why:为什么用

  • 解决访问服务器集群的问题

where:在哪里用

  • 微服务项目中

when:什么时候用

  • 当需要请求服务器集群的时候

how:怎么用

  • 在消费者服务的配置文件中配置
# 配置熔断器超时时间
# 连接超时时长
ribbon.ConnectTimeout: 6000
# 读取数据超时时长
ribbon.ReadTimeout: 6000
# 当前服务器的重试次数【针对请求】
ribbon.MaxAutoRetries: 0
# 重试多少次服务【针对服务】
ribbon.MaxAutoRetriesNextServer: 0
# 是否对所有的请求方式都重试
ribbon.OkToRetryOnAllOperations: false

03.熔断器支持

what:是什么

  • Feign本身也集成Hystrix熔断器

why:为什么使用

  • 统一异常处理

where:在哪里使用

  • 需要做服务降级的时候

when:什么时候使用

  • 当需要对微服务项目的异常做处理的时候

how:怎么使用

  • 在配置文件application.yml中开启feign熔断器支持
  • 编写FallBack处理类,实现FeignClient客户端接口
  • 在@FeignClient注解中,指定FallBack处理类。
  • 测试服务降级效果

实现过程

  • 在配置文件application.yml中开启feign熔断器支持:默认关闭
feign.hystrix.enabled: true # 开启Feign的熔断功能
  • 定义一个类UserServiceFallBack,实现刚才编写的UserFeignClient,作为FallBack的处理类
package com.lxgzhw.service.impl;

import com.lxgzhw.pojo.User;
import com.lxgzhw.service.UserService;
import org.springframework.stereotype.Component;

@Component//需要注意:一定要注入Spring 容器
public class UserServiceFallBack implements UserService {
    @Override
    public User findById(Integer id) {
        User user = new User();
        user.setId(id);
        user.setUsername("用户不存在!!!");
        return user;
    }
}
  • 在@FeignClient注解中,指定FallBack处理类。修改消费者服务的UserService类
package com.lxgzhw.service;

import com.lxgzhw.pojo.User;
import com.lxgzhw.service.impl.UserServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "user-service", fallback = UserServiceFallBack.class)//指定feign调用的服务
public interface UserService {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Integer id);
}

关闭提供者服务

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务

重启测试:http://localhost:8080/consumer/1

springsecurity 需要在每个微服务中部署 spring微服务实战_User_02

04.请求压缩和响应压缩

what:是什么

  • SpringCloudFeign支持对请求和响应进行GZIP压缩,以提升通信过程中的传输速度。

why:为什么要使用

  • 提高传输效率
  • 提高程序性能

where:在哪里使用

  • 使用feign的微服务项目中

when:什么时候用

  • 建议都开启

how:如何使用

  • 通过配置开启请求与响应的压缩功能:
  • 在消费者服务的配置文件中添加
# 开启请求压缩
feign.compression.request.enabled: true
# 开启响应压缩
feign.compression.response.enabled: true
  • 也可以对请求的数据类型,以及触发压缩的大小下限进行设置
# 设置压缩的数据类型
feign.compression.request.mime-types: text/html,application/xml,application/json 
# 设置触发压缩的大小下限
feign.compression.request.min-request-size: 2048

05.配置日志级别

what:是什么

  • 在发送和接收请求的时候,Feign定义了日志的输出定义了四个等级:这里我们配置测试一下。

级别

说明

NONE

不做任何记录

BASIC

只记录输出Http 方法名称、请求URL、返回状态码和执行时间

HEADERS

记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息

FULL

记录Request 和Response的Header,Body和一些请求元数据

why:为什么要使用

  • 当代码出错的时候,便于我们通过日志查看bug

where:在哪里使用

  • 微服务项目

when:什么时候用

  • 需要输出特定日志信息的时候

how:如何使用

  • 在application.yml配置文件中开启日志级别配置
  • 编写配置类,定义日志级别bean。
  • 在接口的@FeignClient中指定配置类
  • 重启项目,测试访问

实现过程

  • 在consumer_service的配置文件中设置com.itheima包下的日志级别都为debug
# com.lxgzhw 包下的日志级别都为Debug
logging.level:
 com.lxgzhw: debug
  • 在consumer_service消费者服务中编写配置类,定义日志级别
package com.lxgzhw.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfiguration {
    @Bean
    public Logger.Level feignLoggerLevel() {
        //记录所有请求和响应的明细,包括头信息,请求体,元数据
        return Logger.Level.FULL;
    }
}
  • 在consumer_service消费者服务的FeignClient中指定配置类。
  • 修改消费者服务的UserService接口
package com.lxgzhw.service;

import com.lxgzhw.config.FeignConfiguration;
import com.lxgzhw.pojo.User;
import com.lxgzhw.service.impl.UserServiceFallBack;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "user-service", fallback = UserServiceFallBack.class, configuration = FeignConfiguration.class)
//指定feign调用的服务
public interface UserService {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Integer id);
}
  • 重启项目,即可看到每次访问的日志

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_03

06.Spring Cloud Gateway 网关

what:是什么

  • Gateway网关是我们服务的守门神,所有微服务的统一入口。
  • Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
  • 在Gateway之前,SpringCloud并不自己开发网关,可能是觉得Netflix公司的Zuul不行吧,然后自己就写了一个,也是替代Netflix Zuul。
  • 其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标和限流。
  • 本身也是一个微服务,需要注册到Eureka

why:为什么使用

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
  • 动态路由
  • Predicates 和 Filters 作用于特定路由
  • 集成 Hystrix 断路器
  • 集成 Spring Cloud DiscoveryClient
  • 简单好用的 Predicates 和 Filters
  • 限流
  • 路径重写
  • 不管是来自客户端的请求,还是服务内部调用。一切对服务的请求都可经过网关。
  • 网关实现鉴权、动态路由等等操作。
  • Gateway是我们服务的统一入口

where:在哪里使用

  • 微服务项目中

when:什么时候使用

  • 当需要做鉴权的时候

how:怎么使用

  • 看下文

术语解释

  • Route(路由):这是网关的基本模块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
  • Predicate(断言):这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容,例如 headers 或参数。
  • Filter(过滤器):这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。

07.网关快速入门

实现步骤

  • 创建SpringBoot工程gateway_server
  • 勾选starter:网关、Eureka客户端
  • 编写基础配置:端口,应用名称,注册中心地址
  • 编写路由规则:唯一表示id,路由url地址,路由限定规则
  • 启动网关服务进行测试

实现过程

  • 创建SpringBoot工程gateway_server

springsecurity 需要在每个微服务中部署 spring微服务实战_spring_04

  • 勾选Starter:网关、Eureka客户端!

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_05

  • 启动引导类开启注册中心Eureka客户端发现
package com.lxgzhw;

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

@SpringBootApplication
@EnableDiscoveryClient// 开启Eureka客户端发现功能
public class GateawayServerApplication {

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

}
  • 编写基础配置
  • 在gateway_server中创建application.yml文件,配置
# 端口
server.port: 10010
# 应用名
spring.application.name: api-gateway
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka
spring:
  cloud:
    gateway:
      # 路由si(集合)
      routes:
        # id唯一标识
        - id: user-service-route
          # 路由服务地址
          uri: http://127.0.0.1:9091
          # 断言
          predicates:
            - Path=/user/**
  • 需要用网关来路由user_service服务,查看服务ip和端口http://127.0.0.1:9091
  • 启动GatewayApplication进行测试:

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_06

  • 修改提供者的UserController,解决json返回xml的问题
package com.lxgzhw.controller;

import com.lxgzhw.pojo.User;
import com.lxgzhw.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping(value = "/{id}", produces = "application/json; charset=UTF-8")
    public User findById(@PathVariable("id") Integer id) {
        return userService.findById(id);
    }
}
  • 重启提供者服务,然后再访问网关路由:http://localhost:10010/user/1

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_07

07.动态路由

what:是什么

  • 刚才路由规则中,我们把路径对应服务地址写死了!
  • 如果服务提供者集群的话,这样做不合理。
  • 应该是根据服务名称,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由!

why:为什么使用

  • 解决url硬编码问题

where:在哪里用

  • 微服务项目

when:什么时候用

  • 网关访问服务器集群的时候

how:怎么实现

  • 修改映射配置:通过服务名称获取
  • 因为已经配置了Eureka客户端,可以从Eureka获取服务的地址信息,修改application.yml文件如下
# 端口
server.port: 10010
# 应用名
spring.application.name: api-gateway
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka
# 注解版
spring:
  cloud:
    gateway:
      # 路由si(集合)
      routes:
        # id唯一标识
        - id: user-service-route
          # 路由地址
          # uri: http://127.0.0.1:9091
          # 采用lb协议,会从Eureka注册中心获取服务请求地址
          # 路由地址如果通过lb协议加服务名称时,会自动使用负载均衡访问对应服务
          # 规则:lb协议+服务名称
          uri: lb://user-service
          # 路由拦截地址(断言)
          predicates:
            - Path=/user/**
  • 路由配置中uri所用的协议为lb时,gateway将把user-service解析为实际的主机和端口,并通过Ribbon进行负载均衡。
  • 启动GatewayApplication测试:http://localhost:10010/user/1
  • 这次gateway进行路由时,会利用Ribbon进行负载均衡访问。日志中可以看到使用了负载均衡器。

08.路由前缀

what:是什么

  • 给路由添加一个前缀或者去除一个前缀
  • 是一种反爬虫策略

why:为什么要学习

  • 添加前缀:防止我们的域名被别人猜测
  • 去除前缀:添加无用的前缀以达到迷惑爬虫的效果

where:在哪里使用

  • 在使用了gateaway的服务器的配置文件中配置

when:什么时候使用

  • 需要考虑反爬虫的时候使用

how:怎么使用

  • 添加前缀
  • 在gateway中可以通过配置路由的过滤器PrefixPath 实现映射路径中的前缀添加。
  • 可以起到隐藏接口地址的作用,避免接口地址暴露。
spring:
 cloud:
   gateway:
     routes:
       - id: user-service-route # 路由id,可以随意写
         # 代理服务地址;lb表示从Eureka中获取具体服务
         uri: lb://user-service
         # 路由断言,配置映射路径
         predicates:
           - Path=/**
         # 请求地址添加路径前缀过滤器
         filters:
           - PrefixPath=/user
  • 去除前缀
  • 在gateway中通过配置路由过滤器StripPrefix,实现映射路径中地址的去除。
  • 通过StripPrefix=1来指定路由要去掉的前缀个数。
  • 如:路径/api/user/1将会被路由到/user/1。
spring:
 cloud:
   gateway:
     routes:
       - id: user-service-route # 路由id,可以随意写
         # 代理服务地址;lb表示从Eureka中获取具体服务
         uri: lb://user-service
         # 路由断言,配置映射路径
         predicates:
           - Path=/**
         # 去除路径前缀过滤器
         filters:
           - StripPrefix=1

09.过滤器

what:是什么

  • 过滤器作为网关的其中一个重要功能,就是实现请求的鉴权。
  • 前面的路由前缀章节中的功能也是使用过滤器实现的。
  • Gateway自带过滤器有几十个,常见自带过滤器有:

过滤器名称

说明

AddRequestHeader

对匹配上的请求加上Header

AddRequestParameters

对匹配上的请求路由

AddResponseHeader

对从网关返回的响应添加Header

StripPrefix

对匹配上的请求路径去除前缀

PrefixPath

对匹配上的请求路径添加前缀

详细说明官方链接

why:为什么用

  • 实现请求的鉴权

where:在哪里用

  • 使用gateaway作为网关的微服务项目

when:什么时候用

  • 请求鉴权:如果没有访问权限,直接进行拦截
  • 异常处理:记录异常日志
  • 服务调用时长统计

how:怎么用

  • 看下文

**过滤器类型:**Gateway有两种过滤器

  • 局部过滤器:只作用在当前配置的路由上。
  • 全局过滤器:作用在所有路由上。

配置全局过滤器:

  • 对输出的响应设置其头部属性名称为i-love,值为lxgzhw
  • 修改gateaway_server的配置文件
# 端口
server.port: 10010
# 应用名
spring.application.name: api-gateway
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka
# 注解版
spring:
  cloud:
    gateway:
      # 配置全局默认过滤器
      default-filters:
        # 往响应过滤器中加入信息
        - AddResponseHeader=i-love,lxgzhw
      # 路由si(集合)
      routes:
        # id唯一标识
        - id: user-service-route
          # 路由地址
          # uri: http://127.0.0.1:9091
          # 采用lb协议,会从Eureka注册中心获取服务请求地址
          # 路由地址如果通过lb协议加服务名称时,会自动使用负载均衡访问对应服务
          # 规则:lb协议+服务名称
          uri: lb://user-service
          # 路由断言,配置映射路径
          predicates:
            - Path=/user/**
          # 请求地址添加路径前缀过滤器
#          filters:
#            - PrefixPath=/user
  • 重启网关服务器,查看浏览器响应头信息:http://localhost:10010/user/1

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_08

执行顺序(了解)

  • Spring Cloud Gateway 的 Filter 的执行顺序有两个:“pre” 和 “post”。
  • “pre”和 “post” 分别会在请求被执行前调用和被执行后调用。
  • 这里的 prepost可以通过过滤器的 GatewayFilterChain 执行filter方法前后来实现。

10.自定义全局过滤器[重点]

需求:模拟登录校验

实现步骤

  • 在gateway_server中,全局过滤器类MyGlobalFilter,实现GlobalFilter和 Ordered接口
  • 编写业务逻辑代码判断:【过滤器必须注入SpringIOC容器中】
  • 如果请求中有token参数,则认为请求有效,放行,
  • 如果没有则拦截提示未授权。
  • 访问接口测试,加token和不加token。

实现过程

  • 在gateway_server中,全局过滤器类MyGlobalFilter,实现GlobalFilter和 Ordered接口
package com.lxgzhw.filter;

import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("-----------------全局过滤器MyGlobalFilter---------------------");
        //1、获取参数中的token,以及token的值
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        //2、如果token的值为空,则拦截
        if (StringUtils.isBlank(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    /**
     * 定义过滤器执行顺序
     * 返回值越小,越靠前执行
     *
     * @return 顺序整数
     */
    @Override
    public int getOrder() {
        return 0;//
    }
}
  • 重启网关服务,分别访问

11.Spring Cloud Config 配置中心

what:是什么

  • 分布式系统中,由于服务数量非常多,配置文件分散在不同微服务项目中,管理极其不方便。
  • 为了方便配置文件集中管理,需要分布式配置中心组件。
  • 在Spring Cloud中,提供了Spring Cloud Config
  • 它支持配置文件放在配置服务的本地,也支持配置文件放在远程仓库Git(GitHub、码云)。
  • 配置中心本质上是一个微服务,同样需要注册到Eureka服务中心!
  • 一句话概括:统一管理所有微服务配置文件的微服务
  • 配置中心,也是一个微服务,需要注册到注册中心

why:为什么使用

  • 统一管理配置文件

where:在哪里使用

  • 微服务项目

when:什么时候用

  • 配置文件较多的时候

how:怎么使用

  • 配置文件集中放在码云
  • 配置中心获取码云配置文件
  • 用户服务获取配置中心文件

12.搭建配置中心gitee仓库

远程Git仓库

  • 知名的Git远程仓库有国外的GitHub和国内的码云(gitee);
  • GitHub主服务在外网,访问经常不稳定,如果希望服务稳定,可以使用码云;
  • 码云访问地址:http://gitee.com

创建远程仓库

  • 首先使用码云上的git仓库需要先注册账户
  • 账户注册完成,然后使用账户登录码云控制台并创建公开仓库!
  • 配置仓库 名称和路径!

创建配置文件

  • 在新建的仓库中创建需要被统一配置管理的配置文件
  • 配置文件的命名方式:{application}-{profile}.yml或{application}-{profile}.properties
  • application为应用名称
  • profile用于区分开发环境dev,测试环境test,生产环境pro等
  • 开发环境 user-dev.yml
  • 测试环境 user-test.yml
  • 生产环境 user-pro.yml
  • 将user-service工程里的配置文件application.yml内容复制作为user-dev.yml文件内容!
  • 注意:名字必须用中划线,如果为下划线"user_dev.yml"则无法访问
  • 创建完user-dev.yml配置文件之后,gitee中的仓库如下:

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_09

13.搭建配置中心微服务

实现步骤

  • 创建配置中心SpringBoot项目config_server
  • 勾选Starter:配置中心,Eureka客户端
  • 在启动引导类上加@EnableConfigServer注解
  • 修改配置文件:端口,应用名称,注册中心地址,码云仓库地址
  • 启动测试,测试配置文件实时同步

实现过程

  • 创建配置中心SpringBoot项目config_server!

springsecurity 需要在每个微服务中部署 spring微服务实战_微服务_10

  • 勾选Starter坐标依赖:配置中心starter,Eureka客户端starter!

springsecurity 需要在每个微服务中部署 spring微服务实战_User_11

  • 启动类:创建配置中心工程config_server的启动类ConfigServerApplication
package com.lxgzhw;

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

@SpringBootApplication
@EnableDiscoveryClient//开启Eureka客户端发现功能
@EnableConfigServer //开启配置服务支持
public class ConfigServerApplication {

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

}
  • 配置文件:创建配置中心工程config_server的配置文件application.yml
# 端口
server.port: 12000
# 应用名称
spring.application.name: config-server
# git仓库地址
spring.cloud.config.server.git.uri: https://gitee.com/lxgzhw/spring_cloud_config.git
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka
  • 注意:上述spring.cloud.config.server.git.uri是在码云创建的仓库地址
  • 启动测试:启动eureka注册中心和配置中心,访问:http://localhost:12000/user-dev.yml
  • 查看能否输出码云存储管理的user-dev.yml文件
  • 并且可以在gitee上修改user-dev.yml,然后刷新上述测试地址也能及时更新数据

springsecurity 需要在每个微服务中部署 spring微服务实战_spring_12

14.服务去获取配置中心配置

关于application.yml和bootstrap.yml文件的说明:

  • bootstrap.yml文件是SpringBoot的默认配置文件,而且其加载时间相比于application.yml更早。
  • bootstrap.yml和application.yml都是默认配置文件,但定位不同
  • bootstrap.yml相当于项目启动的引导文件
  • application.yml文件是微服务的常规配置参数,变化比较频繁
  • 搭配spring-cloud-config使application.yml的配置可以动态替换。

目标:改造user_service工程,配置文件不再由微服务项目提供,而是从配置中心获取。

实现步骤:

  • 在user_service服务中,添加Config的starter依赖
  • 删除application.yml配置文件,新增bootstrap.yml配置文件
  • 配置bootstrap.yml配置文件:
  • 配置中心相关配置(配置文件前缀、后缀,仓库分支,是否开启配置中心)
  • 注册中心地址
  • 启动服务,测试效果

实现过程:

  • 添加依赖
<!--spring cloud 配置中心-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
  • 修改配置
  • 删除user_service工程的application.yml文件
  • 创建user_service工程bootstrap.yml配置文件,配置内容如下
# 注册中心地址
eureka.client.service-url.defaultZone: http://127.0.0.1:10086/eureka

# 配置中心相关配置
# 使用配置中心
spring.cloud.config.discovery.enabled: true
# 配置中心服务id
spring.cloud.config.discovery.service-id: config-server
# 与远程仓库中的配置文件的application和profile保持一致,{application}-{profile}.yml
spring.cloud.config.name: user
spring.cloud.config.profile: dev
# 远程仓库中的分支保持一致
spring.cloud.config.label: master
  • 启动测试:
  • 依次启动:注册中心、配置中心、用户中心user_service!
  • 如果启动没报错,其实已经使用上配置中心内容了
  • 可以在消费者服务中心查看也可以检验user_service的服务!
  • 访问:http://localhost:8080/consumer/1

配置中心存在的问题

  • 我们对于Git仓库中的配置文件的修改,并没有及时更新到user-service微服务,只有重启用户微服务才能生效。
  • SpringCloud Bus,解决上述问题,实现配置自动更新。

15.Spring Cloud Bus 消息总线

what:是什么

  • Bus是用轻量的消息代理将分布式的节点连接起来,可以用于**广播配置文件的更改**或者服务的监控管理。
  • Bus可以为微服务做监控,也可以实现应用程序之间互相通信。
  • Bus可选的消息代理(消息队列)RabbitMQ和Kafka。
  • 广播出去的配置文件服务会进行本地缓存。

why:为什么使用

  • 帮我们解决配置自动更新的问题

where:在哪里使用

  • 微服务项目

when:什么时候使用

  • 需要解决配置自动更新的时候

how:怎么使用

  • 看下文

16.整合案例

目标:消息总线整合入微服务系统,实现配置中心的配置自动更新。不需要重启微服务。

改造配置中心:改造步骤:

  • 在config_server中,加入Bus和RabbitMQ的依赖
  • 修改配置文件:RabbitMQ服务地址,触发配置文件更改接口

实现过程

  • 在config_server项目中加入Bus相关依赖
<!--消息总线依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-bus</artifactId>
</dependency>
<!--RabbitMQ依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
  • 在config_server项目中修改application.yml
# RabbitMQ的服务地址
spring.rabbitmq.host: 192.168.200.128
spring.rabbitmq.port: 5672
spring.rabbitmq.username: guest
spring.rabbitmq.password: guest

# 触发配置文件广播的地址actuator的endpoint
management.endpoints.web.exposure.include: bus-refresh

改造用户服务:改造步骤:

  • 在user-service中,加入Bus和RabbitMQ的依赖
  • 修改配置文件:RabbitMQ服务地址
  • 在需要刷新配置的类上加@RefreshScope注解
  • 测试效果

实现过程:

  • 在用户微服务user_service项目中加入Bus相关依赖
<!--消息总线依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-bus</artifactId>
</dependency>
<!--RabbitMQ依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
  • 修改user_service项目的bootstrap.yml
# RabbitMQ的服务地址
spring.rabbitmq.host: 192.168.200.128
spring.rabbitmq.port: 5672
spring.rabbitmq.username: guest
spring.rabbitmq.password: guest
  • 改造用户微服务user_service项目的UserController
@RestController
@RequestMapping("/user")
@RefreshScope //刷新配置
public class UserController {

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

   @Value("${test.hello}")
   private String name;
   
   @Autowired
   UserService userService;
   //查询所有
   @RequestMapping("/findAll")
   public List<User> findAll() {
       return userService.findAll();
   }
   //根据id查询
   @RequestMapping("/findById")
   public User findById(Integer id) {
       System.out.println("服务【"+port+"】被调用");
       User user = userService.findById(id);
       user.setNote("服务【"+port+"】被调用");
       user.setName(name);
       return user;
   }

}

测试目标:当我们修改Git仓库的配置文件,用户微服务是否能够在不重启的情况下自动更新配置文件信息。

  • 依次启动Eureka注册中心,配置中心,用户微服务!
  • 访问用户微服务查看输出结果!
  • 修改Git仓库中配置文件内容!
  • 使用Postman工具发送POST请求,地址:http://127.0.0.1:12000/actuator/bus-refresh。刷新配置
  • 访问服务接口,浏览器查看输出结果!

说明:

  • Postman或者RESTClient是一个可以模拟浏览器发生各种请求的工具
  • 请求地址http://127.0.0.1:12000/actuator/bus-refresh中actuator是固定的,bus-refresh对应的是配置中心的config_server中的application.yml文件的配置项include的内容
  • http://127.0.0.1:12000/actuator/bus-refresh

消息总线实现消息分发过程:

  • 请求地址访问配置中心的消息总线
  • 消息总线接收到请求
  • 消息总线向消息队列发送消息
  • user-service微服务会监听消息队列
  • user-service微服务接到消息队列中消息后
  • user-service微服务会重新从配置中心获取最新配置信息