springboot 使用 feign

按之前的文章,eureka 服务集群搭好了,eureka 客户端也集成到 springboot 中了。
那么接下来就是具体具体具体的业务接口调用了。
对于 eureka 这些都属于外网的基础,集成完成即可,而 feign 不同,那是需要我们实际编码的,所以得掌握它的具体使用方法,故本文的标题是 “使用feign”。

进入正题,关于使用 feign 主要包含如下几点:

  1. 工程集成 feign 添加pom依赖
  2. 注解开启 feign 客户端支持
  3. 有关 feign 的配置文件参数配置
  4. 编写 feign 具体的 Java 调用类、设置 feign 调用的服务名,指定 Hystrix 熔断托底处理类、编写 Hystrix 熔断托底处理类

正文内容不多,篇幅主要被代码示例占用。

一、添加依赖
本文使用的 springboot 版本 2.1.8.RELEASE

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

二、注解启用
注解 @EnableFeignClients

@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ShanhyService2Application {

	public static void main(String[] args) {
		SpringApplication.run(ShanhyService2Application.class, args);
	}

}

三、属性配置文件

# 是否启用httpclient
feign.httpclient.enabled=false
# 是否启用httpok(性能比httpclient高)
feign.okhttp.enabled=true
# 是否启用hystrix
feign.hystrix.enabled=true
# 请求连接超时时间(毫秒)
feign.httpclient.connection-timeout=3000

四、编写 Restful 接口调用类
使用Feign 调用 Restful 接口,feign 内部基于 ribbon 实现负载均衡,无需做特殊配置处理。
这块的代码多说两句:
1.建议将提供服务的业务,Controller 抽象接口接口出来,并作为一个独立的 module 工程(包含API返回的一些VO类)。
2.接口调用方,也就是 FeignClient 端的工程,也直接引入服务提供方抽象的 API 接口依赖。
3.这样服务调用方 FeignClient 创建接口类继承依赖进来的 API 接口即可(不用重复的定义 GetMapping PostMapping RequestMapping 那一堆方法)
4.@FeignClient 建议使用 fallbackFactory 属性,而不是 fallback 属性。因为前者可以操作异常信息,可操作性相对更强一些。变成层面也没有增加什么复杂性,只不过匿名类的方式比 fallback 略显不够直观(这个根据自己实际情况选择)。

为了示范代码,下面是几个 Java 类示例:

/**
 * 服务接口定义
 * 
 * @author SHANHY
 *
 */
@RequestMapping("/example")
public interface ExampleApi {

	/**
	 * 漫天飞的帖子说这里不支持GetMapping和PathVariable还得必须设置value
	 * (我并没发现这个问题)
	 * 为什么都喜欢无脑拷贝帖子,就算曾经有bug,难道永远都有吗
	 * 
	 * @param id
	 * @return
	 */
	@GetMapping("/test10/{id}")
	public ResultVO demo10(@PathVariable String id);

}

/**
 * 声明式服务<br/>
 * Feign+Hystrix 熔断降级<br/>
 * 其他业务模块可以直接依赖引用,通过调用接口即可完成服务的远程调用,open-feign会对此类做动态代理
 * 
 * @FeignClient 中的 name 表示要调用的服务的实例名称(在eureka中的名称)
 * @FeignClient 中的 fallbackFactory 表示调用服务出现问题时可以打印出相关日志
 * 
 * 
 * @author SHANHY
 *
 */
@FeignClient(name = "shanhy-example1", path = "/shanhy-example1", fallbackFactory = ExampleHystrixFeignFallBackFactory.class)
public interface ExampleFeignClient extends ExampleApi {

}
/**
 * 熔断降级托底实现
 * 
 * @author SHANHY
 *
 */
@Component // @Component 这个不能缺失,否则会报错 No fallbackFactory instance of type class
public class ExampleHystrixFeignFallBackFactory implements FallbackFactory<ExampleFeignClient> {

	private static final Logger LOG = LoggerFactory.getLogger(ExampleHystrixFeignFallBackFactory.class);

	@Override
	public ExampleFeignClient create(Throwable cause) {

		LOG.error("fallback; reason was: " + cause.getMessage(), cause);

		return new ExampleFeignClient() {

			@Override
			public ResultVO demo10(String id) {
				return ResultVO.FAIL;
			}
		};
	}

}

下面的代码是调用接口测试验证的方法片段:

	@GetMapping("/feigntest")
	public String feign(String msg) {
		ResultVO res = exampleFeignClient.demo10(StringUtils.defaultIfBlank(msg, "Hello"));
		String result = "SHOW,CODE=".concat(res.getCode()).concat(",MSG=").concat(res.getMessage());
		if(res.getData() != null)
			result = result.concat(",DATA=").concat(res.getData().toString());
		return result;
	}

最后是服务提供方的Controller 实现:

/**
 * 示例
 * 
 * @author 单红宇
 *
 */
@RestController
public class ExampleController implements ExampleApi  {
	
	private static final Logger LOG = LoggerFactory.getLogger(ExampleController.class);

	@Override
	public ResultVO demo10(String id) {
		HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
	    
		LOG.info("RemoteAddr={}", request.getRemoteAddr());
		return new ResultVO("id=".concat(id));
	}

}

注解 @FeignClient 的主要属性说明:

name: 指定要调用的微服务的名字,用于服务发现,必填
value: 同name属性,alias for name
url: url一般用于调试,可以手动指定调用的绝对地址
configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException,默认为false
fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
path: 定义当前FeignClient的统一前缀,设置context-path的服务,这个值如果不注意配置就404了

思路建议划重点:
方法中的 request 我使用的是 RequestContextHolder 的方式获取的,你可以封装一个静态方法使用。如果你把 request 放到参数里,或者通过类属性注入的方式,实际上也是常用的。但是这样的话,我们抽象的 ExampleApi 接口,就有些侵入性了不够干净。所以我本人的建议是抽象的 ExampleApi 接口,里面只包含方法、常用数据类型和数据交换的 VO 对象。


写在最后
默认情况下,访问http://IP:PORT/actuator/hystrix.stream 是会返回404,这是因为Feign虽然整合了Hystrix,但并没有整合Hystrix的监控。如需使用Hystrix Stream进行监控,找一下度娘 “Feign Hystrix Dashboard”。


(END)

发布了378 篇原创文章 · 获赞 1419 · 访问量 632万+

猜你喜欢

转载自blog.csdn.net/catoop/article/details/101011782