学习spring cloud,使用fegin和hystric进行熔断,遇到了一些细节问题导致失败,下面是正确的使用步骤:
1.pom依赖及熔断配置
<dependencies>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
hystrix必须引入,与openfegin配合使用;我在application.yml中使用了mybatis等,所以还要额外引入MySQL的依赖
feign:
hystrix:
enabled: true # 启动hystrix熔断机制
hystrix:
command:
default:
execution:
timeout:
enabled: false
isolation:
thread:
timeoutInMilliseconds: 2000
ribbon:
ConnectionTimeOut: 6000
ReadTimeOut: 6000
下面的代码里没有直接用到ribbon,也不清楚fegin是否会读取这里的ribbon配置,但是fegin一定会使用ribbon,所以这里的连接和读取超时都设置成了6秒,而hystrix设置成了2秒
2.启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
@EnableFeignClients
@EnableHystrix
public class ConsumerApplication {
public static void main(String[] args)
{
SpringApplication.run(ConsumerApplication.class,args);
}
}
在没有使用fegin之前,在上述代码中还使用了org.springframework.web.client.RestTemplate,这可能会导致fegin中的hystrix失效,不要注入别的Bean
3.消费者类
import com.itheima.client.UserClient;
import com.itheima.domain.User;
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("consumer") #路径
public class ConsumerController {
@Autowired # 注入一个userClient,下面会介绍
private UserClient userClient;
@GetMapping("{id}") # 方法,可以辅助获得参数
public String getHello(@PathVariable("id") int id) {
return userClient.getHello(id);
}
用来调用生产服务的服务者,这里不要引入其他的ribbon中的对象,例如DiscoveryClient等,不然熔断会失效
4.userClient
import client.impl.UserClientImpl;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "user-service", fallbackFactory = UserClientImpl.class)
public interface UserClient {
@GetMapping("hello/{id}")
public String getHello(@PathVariable("id") int id);
}
必须有一个工厂类实现userClient;同时,userClient能找到user-service中的hello/xxx所对应的方法,假设这个方法返回一个字符串
5.userClientImpl
import client.UserClient;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
@Component
public class UserClientImpl implements FallbackFactory<UserClient>{
@Override
public UserClient create(Throwable cause) {
return new UserClient() {
@Override
public String getHello() {
return "circuit in UserClient,getHello";
}
};
}
}
这里实现了真正的熔断方法
6.服务提供类
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("hello")
public class HelloController {
@GetMapping("{id}")
public String hello(@PathVariable("id") int id){
return "hello,spring boot!"+id;
}
}
7.测试
首先开启服务类HelloController和消费类ConsumerController,根据3中的注解,访问consumer/+任意数字,就就通过4中的userClient映射到HelloController的hello方法,得到正确的字符串;
现在关闭服务类,或者从上一部开始就不开启服务类,就会触发5中的熔断方法,返回“circuit in UserClient,getHello”
8.总结
代码逻辑很简单,主要问题处在3中,错误注入了其他的ribbon的组件,导致熔断无法触发