SpringCloud的使用

一、SpringCloud介绍


1.1 微服务架构

微服务架构的提出者:马丁福勒

Microservices

简而言之,微服务架构样式[1]是一种将单个应用程序开发为一组小服务的方法,每个小服务都在自己的进程中运行并与轻量级机制(通常是HTTP资源API)进行通信。这些服务围绕业务功能构建,并且可以由全自动部署机制独立部署。这些服务的集中管理几乎没有,它可以用不同的编程语言编写并使用不同的数据存储技术。

1、 微服务架构只是一个样式,一个风格。

2、 将一个完整的项目,拆分成多个模块去分别开发。

3、 每一个模块都是单独的运行在自己的容器中。

4、 每一个模块都是需要相互通讯的。 Http,RPC,MQ。

5、 每一个模块之间是没有依赖关系的,单独的部署。

6、 可以使用多种语言去开发不同的模块。

7、 使用MySQL数据库,Redis,ES去存储数据,也可以使用多个MySQL数据库。

总结:将复杂臃肿的单体应用进行细粒度的划分,每个拆分出来的服务各自打包部署。

1.2 SpringCloud介绍

  • SpringCloud是微服务架构落地的一套技术栈。

  • SpringCloud中的大多数技术都是基于Netflix公司的技术进行二次研发。

  • SpringCloud的中文社区网站:http://springcloud.cn/

  • SpringCloud的中文网:Spring Cloud中文网-官方文档中文版

  • 八个技术点:

    • Eureka - 服务的注册与发现

    • Ribbon - 服务之间的 负载均衡

    • Feign - 服务之间的通讯

    • Hystrix - 服务的线程隔离以及断路器

    • Zuul - 服务网关

    • Stream - 实现MQ的使用

    • Config - 动态配置

    • Sleuth - 服务追踪

二、服务的注册与发现-Eureka【重点


2.1 引言

Eureka就是帮助我们维护所有服务的信息,以便服务之间的相互调用

Eureka

 

2.2 Eureka的快速入门

2.2.1 创建EurekaServer

此案例中springboot版本为2.6.2,cloud版本为2021.0.0

创建一个父工程,并且在父工程中指定SpringCloud的版本,并且将packaging修改为pom

<packaging>pom</packaging>
​
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

创建eureka的server,创建SpringBoot工程,并且导入依赖,在启动类中添加注解,编写yml文件

导入依赖

<dependencies>
    <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-web</artifactId>
    </dependency>
</dependencies>

启动类添加注解

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

编写yml配置文件

server:
  port: 8761      # 端口号
​
eureka:
  instance:
    hostname: localhost   # localhost
  client:
    # 当前的eureka服务是单机版的
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2.2.2 创建EurekaClient

创建Maven工程,修改为SpringBoot

导入依赖

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

在启动类上添加注解

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

编写配置文件

# 指定Eureka服务地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
​
#指定服务的名称
spring:
  application:
    name: CUSTOMER

 

2.2.3 测试Eureka

创建了一个Search搜索模块,并且注册到Eureka

使用到EurekaClient的对象去获取服务信息

@Autowired
private EurekaClient eurekaClient;

正常RestTemplate调用即可

@GetMapping("/customer")
public String customer(){
    //1. 通过eurekaClient获取到SEARCH服务的信息
    InstanceInfo info = eurekaClient.getNextServerFromEureka("SEARCH", false);
​
    //2. 获取到访问的地址
    String url = info.getHomePageUrl();
    System.out.println(url);
​
    //3. 通过restTemplate访问
    //String result = restTemplate.getForObject(url + "/search", String.class);
​
    //4. 返回
    return result;
}

2.3 Eureka的安全性

实现Eureka认证

导入依赖

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

编写配置类

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
​
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 忽略掉/eureka/**
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

编写配置文件

# 指定用户名和密码
spring:
  security:
    user:
      name: root
      password: root

其他服务想注册到Eureka上需要添加用户名和密码

eureka:
  client:
    service-url:
      defaultZone: http://用户名:密码@localhost:8761/eureka

2.4 Eureka的高可用

如果程序的正在运行,突然Eureka宕机了。

  • 如果调用方访问过一次被调用方了,Eureka的宕机不会影响到功能。

  • 如果调用方没有访问过被调用方,Eureka的宕机就会造成当前功能不可用。

搭建Eureka高可用

准备多台Eureka

如果想在一台机器上配置多太eureka构建高可用集群,由于都使用localhost会失败,所以此处需要修改hosts文件。

打开系统的windows/system32/drivers/etc/文件夹,找到hosts文件,在最后添加如下内容:

127.0.0.1 server1127.0.0.1 server2

修改application.yml文件

spring:
  application:
    name: myeurekaserver
  security:
    user:
      name: root #设置注册中心的安全用户
      password: root #设置注册中心的安全密码
​
server:
  port: 8761
eureka:
  instance:
    hostname: server1
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://root:root@server2:8762/eureka/
​
  server:
    enable-self-preservation: false #不开启在线保护机制(开发阶段不开启(设置为false))

然后启动当前服务器。

再次修改application.yml

spring:
  application:
    name: myeurekaserver
  security:
    user:
      name: root #设置注册中心的安全用户
      password: root #设置注册中心的安全密码
​
server:
  port: 8762
eureka:
  instance:
    hostname: server2
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://root:root@server1:8761/eureka/
​
  server:
    enable-self-preservation: false #不开启在线保护机制(开发阶段不开启(设置为false))

再启动,如此,就启动了两台服务器,并互相建立了注册和发现。

让服务注册到多台Eureka

eureka:
  client:
    service-url:
      defaultZone: http://root:root@server1:8761/eureka,http://root:root@server2:8762/eureka

其实上面只需要让客户端注册到一台正常运行的服务器上,就会自动注册到其他服务器上。所以上面客户端的配置其实也可以只写一个服务端的地址,如下:

eureka:
  client:
    service-url:
      defaultZone: http://root:root@server1:8761/eureka

2.5 Eureka的细节

EurekaClient启动是,将自己的信息注册到EurekaServer上,EurekaSever就会存储上EurekaClient的注册信息。

当EurekaClient调用服务时,本地没有注册信息的缓存时,去EurekaServer中去获取注册信息。

EurekaClient会通过心跳的方式去和EurekaServer进行连接。(默认30sEurekaClient会发送一次心跳请求,如果超过了90s还没有发送心跳信息的话,EurekaServer就认为你宕机了,将当前EurekaClient从注册表中移除)

eureka:
  instance:
    lease-renewal-interval-in-seconds: 30      #心跳的间隔
    lease-expiration-duration-in-seconds: 90    # 多久没发送,就认为你宕机了

EurekaClient会每隔30s去EurekaServer中去更新本地的注册表

eureka:
  client:
    registry-fetch-interval-seconds: 30 # 每隔多久去更新一下本地的注册表缓存信息

Eureka的自我保护机制,统计15分钟内,如果一个服务的心跳发送比例低于85%,EurekaServer就会开启自我保护机制

  • 不会从EurekaServer中去移除长时间没有收到心跳的服务。

  • EurekaServer还是可以正常提供服务的。

  • 网络比较稳定时,EurekaServer才会开始将自己的信息被其他节点同步过去

eureka:
  server:
    enable-self-preservation: true  # 开启自我保护机制

CAP定理,C - 一致性,A-可用性,P-分区容错性,这三个特性在分布式环境下,只能满足2个,而且分区容错性在分布式环境下,是必须要满足的,只能在AC之间进行权衡。

如果选择CP,保证了一致性,可能会造成你系统在一定时间内是不可用的,如果你同步数据的时间比较长,造成的损失大。

BASE理论:基本可用,软状态,最终一致性。

参考:CAP和BASE理论 - 简书

Eureka就是一个AP的效果,高可用的集群,Eureka集群是无中心,Eureka即便宕机几个也不会影响系统的使用,不需要重新的去推举一个master,也会导致一定时间内数据是不一致。

三、负载均衡的客户端-Ribbon【重点


3.1 引言

Ribbon是帮助我们实现服务和服务负载均衡,ribbon属于客户端负载均衡

客户端负载均衡:customer客户模块,将2个Search模块信息全部拉取到本地的缓存,在customer中自己做一个负载均衡的策略,选中某一个服务。

服务端负载均衡:在注册中心中,直接根据你指定的负载均衡策略,帮你选中一个指定的服务信息,并返回。

Ribbon

 

3.2 Ribbon的快速入门

启动两个search模块

在customer中编写代码:

配置整合RestTemplate和Ribbon

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

在customer中去访问search

@GetMapping("/customer")
public String customer(){
    String result = restTemplate.getForObject("http://SEARCH/search", String.class);
​
    //4. 返回
    return result;
}

3.3 Ribbon配置负载均衡策略

负载均衡策略

  • RandomRule:随机策略

  • RoundribbonRule:轮询策略

  • WeightedResponseTimeRule:默认会采用轮询的策略,后续会根据服务的响应时间,自动给你分配权重

  • BestAvailableRule:根据被调用方并发数最小的去分配

四、声明式服务调用-Feign【重点


4.1 引言

Feign可以帮助我们实现面向接口编程,就直接调用其他的服务,简化开发。

4.2 Feign的快速入门

导入依赖

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

在Appliction类上添加一个注解

@EnableFeignClients

创建一个接口,并且和Search模块做映射

@FeignClient("SEARCH")   // 指定服务名称
public interface SearchClient {
    
    // value -> 目标服务的请求路径,method -> 映射请求方式
    @RequestMapping(value = "/search",method = RequestMethod.GET)
    String search();
​
}

测试使用

@Autowired
private SearchClient searchClient;
​
@GetMapping("/customer")
public String customer(){
    String result = searchClient.search();
    return result;
}

4.3 Feign的传递参数方式

【注意事项】

  • 如果你传递的参数,比较复杂时,默认会采用POST的请求方式。

  • 传递单个参数时,推荐使用@PathVariable,如果传递的单个参数比较多,这里也可以采用@RequestParam,不要省略value属性

  • 传递对象信息时,统一采用json的方式,添加@RequestBody

在Search模块下准备三个接口

@GetMapping("/search/{id}")
public Customer findById(@PathVariable Integer id){
    return new Customer(1,"张三",23);
}
​
@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id,@RequestParam String name){
    return new Customer(id,name,23);
}
​
@PostMapping("/save")            
public Customer save(@RequestBody Customer customer){
    return customer;
}

封装Customer模块下的Controller

@GetMapping("/customer/{id}")
public Customer findById(@PathVariable Integer id){
    return searchClient.findById(id);
}
​
@GetMapping("/getCustomer")
public Customer getCustomer(@RequestParam Integer id, @RequestParam String name){
    return searchClient.getCustomer(id,name);
}
​
@GetMapping("/save")            // 会自动转换为POST请求  405
public Customer save(Customer customer){
    return searchClient.save(customer);
}

再封装Client接口

@RequestMapping(value = "/search/{id}",method = RequestMethod.GET)
Customer findById(@PathVariable(value = "id") Integer id);
​
@RequestMapping(value = "/getCustomer",method = RequestMethod.GET)
Customer getCustomer(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name);
​
@RequestMapping(value = "/save",method = RequestMethod.POST)
Customer save(@RequestBody Customer customer);

测试

4.4 Feign的Fallback

Fallback可以帮助我们在使用Feign去调用另外一个服务时,如果出现了问题,走服务降级,返回一个错误数据,避免功能因为一个服务出现问题,全部失效。

注意:2020年以后的spring-cloud版本已经没有默认支持hystrix,需要手动导入依赖:

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

4.4.1 FallBack方式

创建一个POJO类,实现Client接口。

@Component
public class SearchClientFallBack implements SearchClient {
    @Override
    public String search() {
        return "出现问题啦!!!";
    }
​
    @Override
    public Customer findById(Integer id) {
        return null;
    }
​
    @Override
    public Customer getCustomer(Integer id, String name) {
        return null;
    }
​
    @Override
    public Customer save(Customer customer) {
        return null;
    }
}

修改CLient接口中的注解,添加一个属性。

@FeignClient(value = "SEARCH",fallback = SearchClientFallBack.class)


添加一个配置文件。

feign:
  hystrix:
    enabled: true

4.4.1 FallBackFactory方式

调用方无法知道具体的错误信息是什么,通过FallBackFactory的方式去实现这个功能

FallBackFactory基于Fallback

创建一个POJO类,实现FallBackFactory<Client>

@Component
public class SearchClientFallBackFactory implements FallbackFactory<SearchClient> {
​
    @Autowired
    private SearchClientFallBack searchClientFallBack;
​
    @Override
    public SearchClient create(Throwable throwable) {
        throwable.printStackTrace();
        return searchClientFallBack;
    }
}

修改Client接口中的属性

@FeignClient(value = "SEARCH",fallbackFactory = SearchClientFallBackFactory.class)

五、服务的隔离及断路器-Hystrix【重点


5.1 引言

Hystrix

 

5.2 降级机制实现

导入依赖

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

添加一个注解

@EnableCircuitBreaker


针对某一个接口去编写他的降级方法

@GetMapping("/customer/{id}")
@HystrixCommand(fallbackMethod = "findByIdFallBack")
public Customer findById(@PathVariable Integer id){
    int i = 1/0;
    return searchClient.findById(id);
}
​
// findById的降级方法  方法的描述要和接口一致
public Customer findByIdFallBack(Integer id){
    return new Customer(-1,"",0);
}

在接口上添加注解

@HystrixCommand(fallbackMethod = "findByIdFallBack")


5、 测试一下

效果

 

六、服务的网关-Zuul【重点


6.1 引言

  • 客户端维护大量的ip和port信息,直接访问指定服务

  • 认证和授权操作,需要在每一个模块中都添加认证和授权的操作

  • 项目的迭代,服务要拆分,服务要合并,需要客户端进行大量的变化

  • 统一的把安全性校验都放在Zuul中

zuul

 

6.2 Zuul的快速入门

创建Maven项目,修改为SpringBoot

导入依赖

<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-netflix-zuul</artifactId>
</dependency>

添加一个注解

@EnableEurekaClient
@EnableZuulProxy

编写配置文件

# 指定Eureka服务地址
eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka,http://root:root@localhost:8762/eureka
​
#指定服务的名称
spring:
  application:
    name: ZUUL
​
server:
  port: 80

使用http://localhost/customer/customer发现无法直接测试,会出现异常,原因是新版本不支持ZUUL,需要自己添加配置,修复bug。添加配置类:

@Configuration
public class ZuulConfiguration {
    /**
     * The path returned by ErrorController.getErrorPath() with Spring Boot < 2.5
     * (and no longer available on Spring Boot >= 2.5).
     */
    private static final String ERROR_PATH = "/error";
    private static final String METHOD = "lookupHandler";
​
    /**
     * Constructs a new bean post-processor for Zuul.
     *
     * @param routeLocator    the route locator.
     * @param zuulController  the Zuul controller.
     * @param errorController the error controller.
     * @return the new bean post-processor.
     */
    @Bean
    public ZuulPostProcessor zuulPostProcessor(@Autowired RouteLocator routeLocator,
                                               @Autowired ZuulController zuulController,
                                               @Autowired(required = false) ErrorController errorController) {
        return new ZuulPostProcessor(routeLocator, zuulController, errorController);
    }
​
    private enum LookupHandlerCallbackFilter implements CallbackFilter {
        INSTANCE;
​
        @Override
        public int accept(Method method) {
            if (METHOD.equals(method.getName())) {
                return 0;
            }
            return 1;
        }
    }
​
    private enum LookupHandlerMethodInterceptor implements MethodInterceptor {
        INSTANCE;
​
        @Override
        public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            if (ERROR_PATH.equals(args[0])) {
                // by entering this branch we avoid the ZuulHandlerMapping.lookupHandler method to trigger the
                // NoSuchMethodError
                return null;
            }
            return methodProxy.invokeSuper(target, args);
        }
    }
​
    private static final class ZuulPostProcessor implements BeanPostProcessor {
​
        private final RouteLocator routeLocator;
        private final ZuulController zuulController;
        private final boolean hasErrorController;
​
        ZuulPostProcessor(RouteLocator routeLocator, ZuulController zuulController, ErrorController errorController) {
            this.routeLocator = routeLocator;
            this.zuulController = zuulController;
            this.hasErrorController = (errorController != null);
        }
​
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (hasErrorController && (bean instanceof ZuulHandlerMapping)) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(ZuulHandlerMapping.class);
                enhancer.setCallbackFilter(LookupHandlerCallbackFilter.INSTANCE); // only for lookupHandler
                enhancer.setCallbacks(new Callback[] {LookupHandlerMethodInterceptor.INSTANCE, NoOp.INSTANCE});
                Constructor<?> ctor = ZuulHandlerMapping.class.getConstructors()[0];
                return enhancer.create(ctor.getParameterTypes(), new Object[] {routeLocator, zuulController});
            }
            return bean;
        }
    }
}

6.3 Zuul常用配置信息

6.3.1 Zuul的监控界面

导入依赖

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

编写配置文件

# 查看zuul的监控界面(开发时,配置为*,上线,不要配置)
management:
  endpoints:
    web:
      exposure:
        include: "*"

直接访问

 

6.3.2 忽略服务配置

# zuul的配置
zuul:
  # 基于服务名忽略服务,无法查看 ,如果要忽略全部的服务  "*",默认配置的全部路径都会被忽略掉(自定义服务的配置,无法忽略的)
  ignored-services: eureka
  # 监控界面依然可以查看,在访问的时候,404
  ignored-patterns: /**/search/**

6.3.3 自定义服务配置

# zuul的配置
zuul:
  # 指定自定义服务(方式一 , key(服务名):value(路径))
#  routes:
#    search: /ss/**
#    customer: /cc/**
  # 指定自定义服务(方式二)
  routes:
    cx:   # 自定义名称
      path: /cx/**     # 映射的路径
      serviceId: search   # 服务名称

6.4 Zuul的过滤器执行流程

客户端请求发送到Zuul服务上,首先通过PreFilter链,如果正常放行,会吧请求再次转发给RoutingFilter,请求转发到一个指定的服务,在指定的服务响应一个结果之后,再次走一个PostFilter的过滤器链,最终再将响应信息交给客户端。

过滤器

 

6.5 Zuul过滤器入门

创建POJO类,继承ZuulFilter抽象类

@Component
public class TestZuulFilter extends ZuulFilter {}

指定当前过滤器的类型

@Override
public String filterType() {
    return FilterConstants.PRE_TYPE;
}

指定过滤器的执行顺序

@Override
public int filterOrder() {
    return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
}

配置是否启用

@Override
public boolean shouldFilter() {
    // 开启当前过滤器
    return true;
}

指定过滤器中的具体业务代码

@Override
public Object run() throws ZuulException {
    System.out.println("prefix过滤器执行~~~");
    return null;
}

测试

效果

 

6.6 PreFilter实现token校验

准备访问路径,请求参数传递token

http://localhost/customer/version?token=123


创建AuthenticationFilter

@Component
public class AuthenticationFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
​
    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 2;
    }
​
    @Override
    public boolean shouldFilter() {
        return true;
    }
​
    @Override
    public Object run() throws ZuulException {
        //..
    }
    
}

在run方法中编写具体的业务逻辑代码

@Override
public Object run() throws ZuulException {
    //1. 获取Request对象
    RequestContext requestContext = RequestContext.getCurrentContext();
    HttpServletRequest request = requestContext.getRequest();
​
    //2. 获取token参数
    String token = request.getParameter("token");
​
    //3. 对比token
    if(token == null || !"123".equalsIgnoreCase(token)) {
        //4. token校验失败,直接响应数据
        requestContext.setSendZuulResponse(false);
        requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
    }
    return null;
}

测试

效果

 

七、服务的动态配置-Config【重点


7.1 引言

  • 配置文件分散在不同的项目中,不方便维护。

  • 配置文件的安全问题。

  • 修改完配置文件,无法立即生效。

config

 

7.2 搭建Config-Server

创建Maven工程,修改为SpringBoot

导入依赖

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

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


添加注解

@EnableConfigServer
@EnableEurekaClient


编写配置文件(Git的操作)

spring:
  cloud:
    config:
      server:
        git:
          basedir: D:\basedir    # 本地仓库的地址
          username: nswdxqx1999wxf    #  远程仓库用户名
          password: nswdxqx1999   #   远程仓库密码
          uri: https://gitee.com/migid/myconfig.git       # 远程仓库地址
          search-paths: configs

测试(http://localhost:port/{label}/{application}-{profile}.yml)

效果

 

7.3 搭建Config-Client

导入依赖

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

修改原来的search服务的配置文件

# 指定Eureka服务地址
eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka
​
spring:
  application:
    name: SEARCH
  cloud:
    config:
      profile: dev
      discovery:
        enabled: true
        serviceId: CONFIG-SERVER
      name: mycloudtest
      label: master
​
# CONFIG -> mycloudtest-dev.yml

修改配置名称

修改为bootstrap.yml


修改SearchController.java

@Value("${test_name}")
private String name;
​
@GetMapping("/search")
public String search(){
    return "search:" + port + "-name:" + name;
}

测试:http://localhost/cx/search?token=123

效果

 

 

7.4 使用bus通过rabbitMQ通知刷新配置

修改search配置:

添加依赖:

<!-- 消息总线与rabbitMQ配置-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
​
<!-- 消息传动配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

修改bootstrap.yml文件

spring:
  application:
    name: mysearch
  cloud:
    config:
      profile: dev
      discovery:
        enabled: true
        serviceId: CONFIGSERVER
      name: mycloudtest
      label: master
    bus:
      enabled: true
      trace:
        enabled: true
​
  rabbitmq:
    host: localhost
    username: guest
    password: guest
    port: 5672
server:
  port: 9101
​
​
eureka:
  client:
    service-url:
      defaultZone: http://root:root@localhost:8761/eureka/ # 通过用户名密码连接注册中心
  instance:
    prefer-ip-address: true
​
management:
  endpoints:
    web:
      exposure:
        include: "*" #释放所有的接口,主要释放 /actuator/bus-refresh 接口,该接口需要配置到 WebHooks 用于在提价的配置的时候通知ConfigServer

修改appliction文件

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

再修改SearchController.java,添加注解

@RefreshScope // 动态加载配置

测试效果:

1、打开浏览器:http://localhost:9101/search,查看原来的数据

2、修改git上配置文件内容

3、发送post请求:http://localhost:9002/actuator/bus-refresh

4、再次查看http://localhost:9101/search数据,看是否动态刷新

八、服务的追踪-Sleuth【重点


8.1 引言

在整个微服务架构中,微服务很多,一个请求可能需要调用很多很多的服务,最终才能完成一个功能,如果说,整个功能出现了问题,在这么多的服务中,如何去定位到问题的所在点,出现问题的原因是什么。

  • Sleuth可以获得到整个服务链路的信息。

  • Zipkin通过图形化界面去看到信息。

  • Sleuth将日志信息存储到数据库中。

Sleuth

 

8.2 Sleuth的使用

导入依赖

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

编写配置文件

logging:
  level:
    org.springframework.web.servlet.DispatcherServlet: DEBUG

测试

日志信息
SEARCH:服务名称
e9c:总链路id
f07:当前服务的链路id
false:不会将当前的日志信息,输出其他系统中


8.3 Zipkin的使用

搭建Zipkin的web工程 OpenZipkin · A distributed tracing system,官方推荐直接下载他们提供的jar包运行。

https://github.com/openzipkin/zipkin

下载并启动zipkin-server-2.12.9-exec.jar

启动命令:java -jar zipkin-server-2.12.9-exec.jar


导入依赖

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

编写配置文件

#指定服务的名称
spring:
  sleuth:
    sampler:
      probability: 1   # 采样率,百分之多少的sleuth信息需要输出到zipkin中,默认为0.1,值越大收集越及时,但性能影响也越大
  zipkin:
    base-url: http://localhost:9411/  # 指定zipkin的地址

测试

测试

 

 

九、完整SpringCloud架构图【重点


完整架构图

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxf11211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值