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
测试
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
测试
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>
加@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客户端
- 修改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)
- 给配置中心集群中的子工程添加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上的配置信息。
重启测试
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-plugins enable rabbitmq_management
1.4.在window服务管理中重启服务
再此电脑右键=》管理=》服务 里边重启服务
1.5.打开地址
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响应为空,就表示成功。
测试