LWM

Hystrix延迟和容错库

Gateway微服务网关

Config配置管理中心

Bus动态刷新配置

四、Hystrix延迟和容错库

 SpringCloud默认已为Feign整合了hystrix,所以添加Feign依赖后就不用在添加hystrix依赖了。

1.在Fegin中开启hystrix

修改consumer_server_12000工程的application.properties文件,开启hystrix熔断机制

 #在feign中开启hystrix熔断机制
feign.hystrix.enabled=true

2.创建FeignClient接口实现类

在spc_consumer_server_12000的com.test.feign包中创建实现CourseFeignClient.java的类CourseFeignError.java

 

 

 CourseFeignError.java

package com.test.feign;

import org.springframework.stereotype.Component;

import com.test.po.Course;
import com.test.po.ResponseBean;

//启动Hystrix熔断后回退功能,大体相当于try...catch中catch语句作用
@Component
public class CourseFeignError implements CourseFeignClient {

    @Override
    public ResponseBean<Course> getCourse(String cno) {
        // TODO Auto-generated method stub
        ResponseBean<Course> rb=new ResponseBean<Course>(700,"后端业务节点异常");
        return rb;
    }

}

3.在CourseFeignClient.java中做点修改,给@FeignClient注解后边括号加fallback=CourseFeignError.class

测试

五、Gateway微服务网关

1.新建网关项目模块

在spbcloud_demo父类项目下新建spc_gateway_server_14000

 

 

 2.添加依赖

<!--加入gateway依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!--热部署 gav -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

 

 

 3.添加主启动类

 

 

 

 4.添加属性配置文件application.properties

application.properties

server.port=14000
spring.application.name=gateway-server
#这里起名用驼峰法则,自动会解析成consumer-server
spring.cloud.gateway.routes[0].id=consumerServer
#如果前端访问网关中的路由中Path,那么网关会按照路由信息来匹配相应的uri,实际访问路径就会变成http://127.0.0.1:12000/course/getCourse/100
spring.cloud.gateway.routes[0].uri=http://127.0.0.1:12000
#此路由暴露给前端程序,前端访问时用的路径是http://localhost:14000/course/getCourse/100
spring.cloud.gateway.routes[0].predicates[0]=Path=/course/getCourse/**

 

 

 测试

 

5.动态路由(面向服务路由)

Gateway支持与Eureka整合开发,根据服务名自动从注册中心中获取服务地址并转发请求。这样做不仅能够通过单个端点来访问应用中的所有服务,而且在添加、移除或修改服务时,不用修改Gateway的路由配置。这就是动态路由(面向服务的路由)。

 5.1将网关注册到Eureka中,在spc_gateway_server_14000 子工程中添加Eureka Client的依赖

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

5.2修改spc_gateway_server_14000 的application.properties,将原来的非动态路由写法改成动态路由写法,并且将网关注册到Eureka中

application.properties

server.port=14000
spring.application.name=gateway-server
#这里起名用驼峰法则,自动会解析成consumer-server
spring.cloud.gateway.routes[0].id=consumerServer

#如果前端访问网关中的路由中Path,那么网关会按照路由信息来匹配相应的uri,实际访问路径就会变成http://127.0.0.1:12000/course/getCourse/100
#非动态路由服务写法,无法适应微服务模块真实IP发生变更的情况
#spring.cloud.gateway.routes[0].uri=http://127.0.0.1:12000

#动态路由服务的写法
spring.cloud.gateway.routes[0].uri=lb://consumer-server

#此路由暴露给前端程序,前端访问时用的路径是http://localhost:14000/course/getCourse/100
spring.cloud.gateway.routes[0].predicates[0]=Path=/course/getCourse/**

#让服务API网关注册到eureka服务端
eureka.client.service-url.defaultZone=http://eurekaServer13000:13000/eureka,http://eurekaServer13001:13001/eureka
#使用ip地址向Eureka注册
eureka.instance.prefer-ip-address=true
#上面的配置已经可以使用ip注册了,但显示的还是主机名,所以这里设置显示的注册名
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
#续约时间间隔(秒)
eureka.instance.lease-renewal-interval-in-seconds=10
#续约到期时间(秒)
eureka.instance.lease-expiration-duration-in-seconds=20

测试

 

6.网关熔断处理

不论是服务消费者调用服务提供者时、还是通过网关调用微服务时,都需要进行熔断处理。所以,Gateway也需要使用Hystrix进行熔断处理。也就是Gateway集成Hystrix。

6.1在pom.xml文件中添加Hystrix依赖:spc_gateway_server_14000

<!--加入hystrix的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

6.2新建com.test.controller包,在里边建FallBackController类 spc_gateway_server_14000

 

 在将ResponseBean放进来

 

 FallBackController.java

package com.test.controller;

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

import com.test.po.ResponseBean;

@RestController
@RequestMapping("/fallback")
public class FallBackController {

    @GetMapping("/error")
    public ResponseBean back(){
        ResponseBean rb=new ResponseBean<>(700,"网关熔断");
        return rb;
    }
}

6.3在application.properties中添加配置spc_gateway_server_14000

#部署熔断处理的过滤器
spring.cloud.gateway.routes[0].filters[0].name=Hystrix
spring.cloud.gateway.routes[0].filters[0].args.name=fallbackcmd
spring.cloud.gateway.routes[0].filters[0].args.fallbackUri=forward:/fallback/error

 

 测试

 

六、Config配置管理中心

1.搭建远程GIT仓库

 

初始化readme文件

 

 

 

 

 点击管理

 

 

 填写介绍和选中开源和开源须知后保存

 

 

 2.上传配置文件

吧spc_provider_server_11000和spc_provider_server_11001的application.properties复制粘贴出来,放到电脑任意位置,并且分别改名为spc_provider_server_11000-dev和spc_provider_server_11001-dev

 

 

 

 然后再gitee中上传文件

 

将复制出来的两个配置文件拖拽到上传区域,填写提交信息后提交

 

 

 

 

 

 3.创建SCC服务端

3.1在父工程下,创建 Maven Module 子工程(工程名:spc_config_server_15000;Packaging:jar)

 

 

 

 

3.2在pom.xml文件中添加依赖spc_config_server_15000

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

    <!--热部署 gav -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
3.3创建主启动类spc_config_server_15000

 

 加@EnableConfigServer注解

MyApplication.java

package com.test;

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

@SpringBootApplication
@EnableConfigServer //开启SCC服务器端注解
public class MyApplication {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SpringApplication.run(MyApplication.class, args);
    }

}

3.4添加application.properties配置文件并且添加配置spc_config_server_15000

application.properties

server.port=15000
spring.application.name=config-server
spring.cloud.config.server.git.uri=https://gitee.com/weiming-li/myconfig.git

 

 测试

 

 3.5修改SCC客户端

  1. 修改spc_provider_server_11000工程和spc_provider_server_11001工程,在pom.xml文件中添加SCC的依赖
<!--加入spring-cloud-config的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>

3.6创建bootstrap.properties(spc_provider_server_11000),并且写入配置信息

bootstrap.properties(这里spring.cloud.config.name+spring.cloud.config.profile=git里边放的配置文件名字spc_provider_server_11000-dev)

#应用名称。对应git中文件名称的前半部分
spring.cloud.config.name=spc_provider_server_11000
#开发环境。对应git中文件名称的后半部分
spring.cloud.config.profile=dev
#git分支
spring.cloud.config.label=master
#config server的请求地址
spring.cloud.config.uri=http://localhost:15000

 3.7删除application.properties

 

 

 

 3.8.spc_provider_server_11001同理做配置

测试

 

4.创建配置中心集群

4.1先把spc_config_server_15000复制一份为spc_config_server_15001,并且修改application.properties中的server.port

 4.2集群注册到Eureka(spc_config_server_15000、spc_config_server_15001)

  1. 给配置中心集群中的子工程添加Eureka客户端依赖(spc_config_server_15000、spc_config_server_15001)
<!-- Eureka的客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

给spc_config_server_15000、spc_config_server_15001的application.properties中添加配置(spc_config_server_15000、spc_config_server_15001)

application.properties

#配置服务中心注册到eureka服务端
eureka.client.service-url.defaultZone=http://eurekaServer13000:13000/eureka,http://eurekaServer13001:13001/eureka
#使用ip地址向Eureka注册
eureka.instance.prefer-ip-address=true
#上面的配置已经可以使用ip注册了,但显示的还是主机名,所以这里设置显示的注册名
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

 

 

 测试

4.3从Eureka中读取配置信息

修改spc_provider_server_11000工程和spc_provider_server_11001工程中的bootstrap.properties文件:

spc_provider_server_11000的bootstrap.properties

#应用名称。对应git中文件名称的前半部分
spring.cloud.config.name=spc_provider_server_11000
#开发环境。对应git中文件名称的后半部分
spring.cloud.config.profile=dev
#git分支
spring.cloud.config.label=master
#config server的请求地址
#单个配置中心服务器写法
#spring.cloud.config.uri=http://localhost:15000
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=config-server

#服务生产者注册到eureka服务端
eureka.client.service-url.defaultZone=http://eurekaServer13000:13000/eureka,http://eurekaServer13001:13001/eureka
#使用ip地址向Eureka注册
eureka.instance.prefer-ip-address=true
#上面的配置已经可以使用ip注册了,但显示的还是主机名,所以这里设置显示的注册名
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}

spc_provider_server_11001的bootstrap.properties

#应用名称。对应git中文件名称的前半部分
spring.cloud.config.name=spc_provider_server_11001
#开发环境。对应git中文件名称的后半部分
spring.cloud.config.profile=dev
#git分支
spring.cloud.config.label=master
#config server的请求地址
#单个配置中心服务器写法
#spring.cloud.config.uri=http://localhost:15000
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=config-server

#服务生产者注册到eureka服务端
eureka.client.service-url.defaultZone=http://eurekaServer13000:13000/eureka,http://eurekaServer13001:13001/eureka
#使用ip地址向Eureka注册
eureka.instance.prefer-ip-address=true
#上面的配置已经可以使用ip注册了,但显示的还是主机名,所以这里设置显示的注册名
eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
  • 尽管远程Git上的配置文件中已经有了Eureka配置信息,但是这里仍然要再写一遍。目的是要先将自己注册给Eureka,以便获取Eureka上的配置信息
  • config server的请求地址应该是通过 discovery.enabled:true 来开启服务发现,然后通过service-id:config-server中设置的config server服务名,来获取Git上的配置信息。

重启测试

 

七、Bus动态刷新配置

1.安装rabbitMQ

1.1安装Erlang语言环境

https://github.com/erlang/otp/releases/download/OTP-25.0.4/otp_win64_25.0.4.exe

安装就一顿下一步就行

配置环境变量:

 

 

 PATH:

 

 

 cmd中erl -version查看是否安装成功

1.2.安装rabbitMQ

一顿下一步就行

再此电脑右键=》管理=》服务 里边能看到rabbitMQ就是安装成功

1.3.安装插件

进入rabbitMQ的sbin目录cmd
位置:C:\Program Files\RabbitMQ Server\rabbitmq_server-3.10.7\sbin
rabbitmq-plugins enable rabbitmq_management

1.4.在window服务管理中重启服务

再此电脑右键=》管理=》服务 里边重启服务

1.5.打开地址

http://127.0.0.1:15672/  看到管理界面。用户名和密码都是guest

 

2.一个简单的rabbitMQ的例子

创建一个简单maven项目rmqdemo

加入依赖

<!-- amqp客户端 -->
      <dependency>
          <groupId>com.rabbitmq</groupId>
          <artifactId>amqp-client</artifactId>
          <version>5.6.0</version>
      </dependency>

创建一个包rmqdemo,并且创建两个类,Consumer.java,Producer.java

Consumer.java

package rmqdemo;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

public class Consumer {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 主机地址,默认为localhost
        connectionFactory.setHost("localhost");
        // 连接端口,默认为5672
        connectionFactory.setPort(5672);
        // 连接用户名:默认为guest
        connectionFactory.setUsername("guest");
        // 连接密码:默认为guest
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        // 创建频道
        Channel channel = connection.createChannel();
        // 声明(创建)队列
        /**
         * 参数1:队列名称 参数2:是否定义持久化队列 参数3:是否独占本次连接 参数4:是否在不适用的时候自动删除队列 参数5:队列其他参数
         */
        channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);
        // 创建消费者,并设置消息处理
        DefaultConsumer consumer = new DefaultConsumer(channel) {
            @Override
            /**
             * consumerTag 消息者标签,在channel.basicConsume时候可以指定envelope
             * 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标签(收到消息失败后是否需要重新发送)
             * properties 属性信息body 消息
             */
            public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
                    throws IOException {
                // 路由key
                System.out.println("路由key为:" + envelope.getRoutingKey());
                // 交换机
                System.out.println("交换机为:" + envelope.getExchange());
                // 消息id
                System.out.println("消息id为:" + envelope.getDeliveryTag());
                // 收到的消息
                System.out.println("接收到的消息为:" + new String(body, "utf-8"));
            }
        };
        // 监听消息
        /**
         * basicConsume(String queue,boolean autoAck,Consumer callback) 参数1:队列名称
         * 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动回复
         * 参数3:消息接收到后回调
         */
        channel.basicConsume(Producer.QUEUE_NAME, true, consumer);
        // 不关闭资源,应该一直监听消息
        // channel.close();
        // connection.close();
    }

}

Producer.java

package rmqdemo;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Producer {

    static final String QUEUE_NAME = "simple_queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 主机地址,默认为localhost
        connectionFactory.setHost("localhost");
        // 连接端口,默认为5672
        connectionFactory.setPort(5672);
        // 连接用户名:默认为guest
        connectionFactory.setUsername("guest");
        // 连接密码:默认为guest
        connectionFactory.setPassword("guest");
        // 创建连接
        Connection connection = connectionFactory.newConnection();
        // 创建频道
        Channel channel = connection.createChannel();
        // 声明(创建)队列
        /**
         * 参数1:队列名称 参数2:是否定义持久化队列 参数3:是否独占本次连接 参数4:是否在不适用的时候自动删除队列 参数5:队列其他参数
         */
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);
        // 要发送的信息
        String message = "你好";
        /**
         * 参数1:交换机名称,如果没有指定则使用默认Default Exchage 参数2:路由key,简单模式可以传递队列名称
         * 参数3:消息其他属性 参数4:消息内容
         */
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes("utf-8"));
        System.out.println("已发送消息:" + message);
        // 关闭资源
        channel.close();
        connection.close();

    }

}

测试:Producer.java先运行发送消息,Consumer.java后运行接收消息,同时在rabbitMQ后台查看发送接收情况

 

3.config server端配置

向spc_config_server_15000和spc_config_server_15001添加依赖

<!-- 消息总线依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
        
<!-- 监听依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

4.修改配置文件:向spc_config_server_15000和spc_config_server_15001的application.properties添加配置

#rabbitmq的相关配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#使用bus总线刷新配置文件,配置总线的刷新接口配置
management.endpoints.web.exposure.include=bus-refresh

 

 

 5.修改 spc_provider_server_11000工程和spc_provider_server_11001工程,添加依赖(与config server是一样的)

<!-- 消息总线依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
        
<!-- 监听依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>  

6.修改Controller组件

在spc_provider_server_11000的CourseController.java中加@RefreshScope注解和加一些代码,spc_provider_server_11001也一样

CourseController.java

package com.test.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
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;

import com.test.po.Course;
import com.test.po.ResponseBean;

@RestController
@RequestMapping("/course")
@RefreshScope // 开启动态刷新
public class CourseController {

    // 从配置文件中读取名为msg的建里对应的值
    @Value("${msg}")
    private String msg;

    @GetMapping("/getCourse/{cno}")
    public ResponseBean<Course> getCourse(@PathVariable("cno") String cno) {
        Course c = new Course();
        c.setCno(cno);
        c.setCname("art11000");
        c.setTno("100");
        ResponseBean<Course> rb = new ResponseBean<Course>(c);
        rb.setMsg("success" + msg);
        return rb;
    }

}

 

7.在gitee的myconfig中修改spc_provider_server_11000-dev.properties配置文件

 

 

 添加配置

#测试总线刷新的键值对
msg="abc"

 

 

 提交

同理修改spc_provider_server_11001-dev.properties

提交

8.测试

8.1修改 Git仓库中配置文件内容(修改msg属性值)

8.2在Postman中发送请求:http://localhost:15000/actuator/bus-refresh  (必须是post请求)(刷新消息总线)

8.3发送post请求后,如果postman响应为空,就表示成功。

 

 测试

 

posted on 2023-02-16 17:15  Lwmm  阅读(86)  评论(0编辑  收藏  举报