1.Feign对Hystrix的支持
项目准备:
1. microservice-consumer-movie-feign-with-hystrix
2. microservice-provider-user
3. microservice-discovery-eureka
microservice-consumer-movie-feign-with-hystrix项目结构,如下:
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
application.yml
spring:
application:
name: microservice-consumer-movie-feign-with-hystrix
server:
port: 7901
eureka:
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: http://user:password123@localhost:8761/eureka
instance:
prefer-ip-address: true
ConsumerMovieFeignApplication
package com.itmuch.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker
public class ConsumerMovieFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerMovieFeignApplication.class, args);
}
}
MovieController
package com.itmuch.cloud.controller;
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.RestController;
import com.itmuch.cloud.entity.User;
import com.itmuch.cloud.feign.UserFeignClient;
@RestController
public class MovieController {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping("/movie/{id}")
public User findById(@PathVariable Long id) {
return this.userFeignClient.findById(id);
}
}
UserFeignClient
package com.itmuch.cloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.itmuch.cloud.entity.User;
@FeignClient(name = "microservice-provider-user", fallback = HystrixClientFallback.class)
public interface UserFeignClient {
@RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
}
HystrixClientFallback
package com.itmuch.cloud.feign;
import org.springframework.stereotype.Component;
import com.itmuch.cloud.entity.User;
@Component
public class HystrixClientFallback implements UserFeignClient {
@Override
public User findById(Long id) {
User user = new User();
user.setId(0L);
return user;
}
}
请求http://localhost:7901/movie/1
停掉用户微服务,并且重复请求http://localhost:7901/movie/1
请求http://localhost:7901/health发现短路器已经打开,如下:
2.如何禁用单个FegionClient的Hystrix的支持
在自定义feign配置中加入如下代码:
@Configuration
public class FooConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
我的测试用例:
Configuration2
package com.itmuch.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import feign.Feign;
import feign.auth.BasicAuthRequestInterceptor;
@Configuration
public class Configuration2 {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("user", "password123");
}
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
FeignClient2Fallback
package com.itmuch.cloud.feign;
public class FeignClient2Fallback implements FeignClient2 {
@Override
public String findServiceInfoFromEurekaByServiceName(String serviceName) {
return "haha";
}
}
FeignClient2
package com.itmuch.cloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import com.itmuch.config.Configuration2;
@FeignClient(name = "xxxx", url = "http://localhost:8761/", configuration = Configuration2.class, fallback = FeignClient2Fallback.class)
public interface FeignClient2 {
@RequestMapping(value = "/eureka/apps/{serviceName}")
public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName);
}
启动microservice-discovery-eureka,microservice-consumer-movie-feign-customizing-without-hystrix
请求:http://localhost:7901/microservice-provider-user
停掉microservice-discovery-eureka
请求:http://localhost:7901/microservice-provider-user,可以看出没有返回期望值haha,
所以已经禁用单个FegionClient的Hystrix的支持,没有返回 访问失败时自定义的返回值haha,如下
3. Feign使用fallbackFactory属性打印fallback异常
MovieController
package com.itmuch.cloud.controller;
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.RestController;
import com.itmuch.cloud.entity.User;
import com.itmuch.cloud.feign.UserFeignClient;
@RestController
public class MovieController {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping("/movie/{id}")
public User findById(@PathVariable Long id) {
return this.userFeignClient.findById(id);
}
}
UserFeignClient
package com.itmuch.cloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.itmuch.cloud.entity.User;
@FeignClient(name = "microservice-provider-user", /*fallback = HystrixClientFallback.class, */fallbackFactory = HystrixClientFactory.class)
public interface UserFeignClient {
@RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
public User findById(@PathVariable("id") Long id);
}
HystrixClientFactory
package com.itmuch.cloud.feign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.itmuch.cloud.entity.User;
import feign.hystrix.FallbackFactory;
@Component
public class HystrixClientFactory implements FallbackFactory<UserFeignClient> {
private static final Logger LOGGER = LoggerFactory.getLogger(HystrixClientFactory.class);
@Override
public UserFeignClient create(Throwable cause) {
HystrixClientFactory.LOGGER.info("fallback; reason was: {}", cause.getMessage());
return new UserFeignClientWithFactory() {
@Override
public User findById(Long id) {
User user = new User();
user.setId(-1L);
return user;
}
};
}
}
UserFeignClientWithFactory
package com.itmuch.cloud.feign;
public interface UserFeignClientWithFactory extends UserFeignClient {
}
请求:http://localhost:7901/movie/1
请求:http://localhost:7901/movie/1
停掉用户微服务,再次请求:http://localhost:7901/movie/1
可见在控制台有打印出的异常信息。
注意:fallback 和 fallbackFactory只能用一个!
fallbackFactory可以理解为fallback的增强版,其能够打印fallback异常