1.什么是Feign
总的来说就是ribbion和hystrix的结合体,由于使用restTemplate的麻烦和重复性,所以有了这一个组件包装了ribbion和hystrix,不过需要注意的是底层还是使用ribbion和hystrix,只是使用注解的方式优雅的实现了这个负载均衡和断路器。
2.快速人们
1.配置依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
2.加入注解
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
3.设计消费服务,创建service
@FeignClient里面填写的是需要消费的服务名称
@RequestMapping 这里是feign对springmvc的扩展支持
@RequestParam 必须加value
@RequestHead 必须加value
@RequestBody 不用必须加value
@FeignClient("hello-service")
public interface HelloService {
@RequestMapping("/hello")
String hello();
@RequestMapping("hello1")
public String index1(@RequestParam(value = "name") String name);
@RequestMapping("hello2")
public User index2(@RequestHeader(value = "name") String name);
@RequestMapping("hello3")
public String index3(@RequestBody User user);
}
4.控制器
@RestController
public class ConsumerController {
@Autowired
HelloService helloService;
@RequestMapping(value = "/feign-consumer",method = RequestMethod.GET)
public String helloConsumer() {
return helloService.hello();
}
@RequestMapping(value = "/feign-consumer2",method = RequestMethod.GET)
public String helloConsumer2() {
StringBuilder stringBuilder=new StringBuilder();
User user=new User();
user.setName("llx");
stringBuilder.append(helloService.index1("llg")).append("\n");
stringBuilder.append(helloService.index2("llg")).append("\n");
stringBuilder.append(helloService.index3(user)).append("\n");
return stringBuilder.toString();
}
}
5.配置属性
spring.application.name=feign-consumer
server.port=9001
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/
3.继承特性
为了解决类似于接口与controller重复问题,将统一资源抽象成接口,服务提供者根据此接口提供服务,服务消费者通过此接口和feign直接绑定服务。
好处:不用再重复的写接口的定义
坏处:麻烦,由于依赖maven私有仓库,当接口变动的时候需要改变多出地方
1.首先创建一个新的maven项目,构建接口
@RequestMapping("/refactor")
public interface HelloService {
@RequestMapping("hello4")
public String index1(@RequestParam(value = "name") String name);
@RequestMapping("hello5")
public User index2(@RequestHeader(value = "name") String name);
@RequestMapping("hello6")
public String index3(@RequestBody User user);
}
2.根据依赖的接口对象写服务提供者的Controller对象,在这里通过重写方法可以将注解也继承下来,所以无需再加注解,记得加Controller注解即可
@RestController
public class RefactorHelloController implements HelloService {
@Override
public String index1(@RequestParam String name){
return name;
}
@Override
public User index2(@RequestHeader String name){
User user=new User();
user.setName(name);
return user;
}
@Override
public String index3(@RequestBody User user){
return "User3 : "+user.getName();
}
}
3.服务消费者根据接口只需要继承即可
@FeignClient(value="hello-service")
public interface RefactorHelloService extends HelloService {
}
4.服务消费者通过service进行消费
@RestController
public class ConsumerController {
@Autowired
RefactorHelloService refactorHelloService;
@RequestMapping(value = "/feign-consumer3",method = RequestMethod.GET)
public String helloConsumer3() {
StringBuilder stringBuilder=new StringBuilder();
User user=new User();
user.setName("llx");
stringBuilder.append(refactorHelloService.index1("llg")).append("\n");
stringBuilder.append(refactorHelloService.index2("llg")).append("\n");
//stringBuilder.append(refactorHelloService.index3(user)).append("\n");
return stringBuilder.toString();
}
}
4.Ribbon配置
启动了Feign的时候同时也会启动Ribbion,也就是说@FeignClient(value="hello-servuce")不仅启动了一个名字叫hello-service的客户端,还启动了一个同名的Ribbion客户端
所以只需要在配置文件上配置负载均衡信息即可,切记如果需要配置全局信息只要把代表client信息的hello-servce删除即可
hello-service.ribbion.ConnectTimeout=250 请求连接超时间
hello-service.ribbion.ReadTimeout=1000 请求处理超时时间
heelo-service.ribbion.OkToRetryAllOperations=true 对所有请求都进行重试
heelo-service.ribbion.MaxAutoRetriesNextServer=2 切换实例的重试次数
hello-service.ribbion.MaxAutoRetries=1 对当前实例的重试次数
注意:ribbion的超时与hystrix的超时是不一样的,ribbion的超时说的是重试时候的超时,可以重试调用同一个实例,不然就会调用另外一个实例,所以需要知道的是必须让Hystrix的超时时间大于Ribbion的超时时间,否则断路器打开就不好了。
5.Hystrix配置
使用Feign之后,自动帮我们将所有方法都封装到了Hystrix命令中
全局配置:直接使用默认前缀hystrix.command.default
例如:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
注意:需要Hystrix服务的时候,要确保feign.hystrix.enabled=true有没有打开
禁用Hystrix
全局禁用:feign.hystrix.enabled=false
局部禁用:用过配置类,禁用某个服务客户端
@Configuration
public class DisableHystrixConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilfer(){
return Feign.builder();
}
}
@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {
@RequestMapping("/hello")
String hello();
@RequestMapping("hello1")
public String index1(@RequestParam(value = "name") String name);
@RequestMapping("hello2")
public String index2(@RequestHeader(value = "name") String name);
@RequestMapping("hello3")
public String index3(@RequestBody User user);
}
指令命令配置
采用hystrix.commond.<commonKey>作为前缀,而在Feign中则是把方法名设置为commonkey命令名
例如hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=500
注意:由于使用方法名有重复的风险,所以要么在方法名上尽量不重复,要么在Feign.build上重写
public static String configKey(Class targetType, Method method) {
StringBuilder builder = new StringBuilder();
builder.append(targetType.getSimpleName());
builder.append('#').append(method.getName()).append('(');
Type[] var3 = method.getGenericParameterTypes();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
Type param = var3[var5];
param = Types.resolve(targetType, targetType, param);
builder.append(Types.getRawType(param).getSimpleName()).append(',');
}
if (method.getParameterTypes().length > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.append(')').toString();
}
服务降级配置
相比较于之前的ribbion的配置,使用Feign写服务降级逻辑则有点不一样,首先实现service接口的实现类,然后将此实现类写入@FeignClient的注解属性fallbcak中
@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {
@RequestMapping("/hello")
String hello();
@RequestMapping("hello1")
public String index1(@RequestParam(value = "name") String name);
@RequestMapping("hello2")
public String index2(@RequestHeader(value = "name") String name);
@RequestMapping("hello3")
public String index3(@RequestBody User user);
}
public class HelloServiceFallback implements HelloService {
@Override
public String index1(String name) {
return "error";
}
@Override
public User index2(String name) {
return new User();
}
@Override
public String index3(User user) {
return "error3";
}
}
@FeignClient(value="hello-service",fallback = HelloServiceFallback.class)
public interface RefactorHelloService extends HelloService {
}
6.其他配置
请求压缩
指的是将请求内容和响应内容通过gzip压缩,降低性能损耗
feign.compression.request.enabled=true;
feign.compression.response.enabled=true;
feign.compression.request.mime-types=text/xml,application/xml,application/json 指定压缩的请求数据类型(默认值)
feign.compression.request.min-request-size=2048 只有超过此大小的请求才会被压缩(默认值)
7.日志配置
每一个@FeignClient客户端都自动创建了feign.Logger实例
通过配置可以开启
logging.level.<FeignClient>.xxxx
例如:logging.level.com.llg.demo.HelloService=DEBUG
紧接着还必须继续配置Bean
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class FeignConsumerApplication {
@Bean
Logger.Level feingnLoggerLevel(){
return Logger.Level.FULL;
}
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
还可以通过刚刚使用配置类来局部禁用Hystrix的配置类来配置Bean,可以达到局部配置日志级别的目的。
@Configuration
public class DisableHystrixConfiguration {
@Bean
Logger.Level feingnLoggerLevel(){
return Logger.Level.FULL;
}
@Bean
@Scope("prototype")
public Feign.Builder feignBuilfer(){
return Feign.builder();
}
}
@FeignClient(value = "hello-service",configuration = DisableHystrixConfiguration.class)
public interface HelloServicess {
@RequestMapping("/hello")
String hello();
@RequestMapping("hello1")
public String index1(@RequestParam(value = "name") String name);
@RequestMapping("hello2")
public String index2(@RequestHeader(value = "name") String name);
@RequestMapping("hello3")
public String index3(@RequestBody User user);
}
总结:对于Feign级别有4种
NONE:不记录任何信息
BASIC:仅记录请求方法,URL,响应状态码和执行时间
HEADERS:包括basic还有记录请求和响应的头信息
FULL:记录所有请求数据