ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ***** # 1. 使用Feign实现远程HTTP调用 ``` fegin的github地址: https://github.com/openfeign/feign Feign是一个声明式WebService客户端.使用Feign能让编写WebService客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解. Feign也支持可拔插式的编码器和解码器.Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters. Feign可以与nacos/Eureka和Ribbon组合使用以支持负载均衡. 解决的问题: 1. 代码不可读 2. 复杂的url难以维护 3. 难以相应需求的变化 4. 编程体验不统一 ``` # 2. fegin的使用 ``` 1. 加依赖 compile("org.springframework.cloud:spring-cloud-starter-openfeign") 2. 在启动类或者配置类上加注解 @EnableFeignClients 3. 写配置 使用默认配置 ``` ``` /** * name: 请求服务的名称 */ @FeignClient(name = "ali-pay-service") public interface UserCenterFeginClient { /** * http://ali-pay-service/users/{id} * @param id * @return */ @GetMapping("/users/{id}") String findById(@PathVariable Integer id); } ``` # 3. Feign的组成 ![](https://img.kancloud.cn/57/d0/57d087ca9af2f5b9d5755b833ddc286c_824x395.png) # 4. 细粒度配置自定义 ``` 4-1. 细粒度配置自定义-Java代码方式-指定日志级别 场景: 通过feign请求服务时,打印请求信息的日志 ``` **4-1. Feign的日志级别:** ![](https://img.kancloud.cn/dd/84/dd84b0d36cc545958496e2c4f9c17b2f_768x269.png) **4-2. 代码方式配置日志级别:** ``` /** * name: 请求服务的名称 */ @FeignClient(name = "ali-pay-service", configuration = UserCenterFeignConfiguration.class) public interface UserCenterFeginClient { /** * http://ali-pay-service/users/{id} * @param id * @return */ @GetMapping("/users/{id}") String findById(@PathVariable Integer id); } ``` ``` /** * 自定义日志级别 * 若改类上面有@Configuration注解,就要把它放在启动类之外的包内 * 原因:父子上下文的关系,会被@ComponentScan扫描到用在所有的feignClient上 * 出现一些奇怪的问题,所以建议不要加@Configuration注解 */ public class UserCenterFeignConfiguration { @Bean public Logger.Level level() { //让feign打印所有请求的细节 return Logger.Level.FULL; } } ``` ``` logging: level: # 自定义feign的日志级别是建立在debug基础上的,若为其他如info,则不会打印任何日志 com.example.feginclient.UserCenterFeginClient: debug ``` **4-3. 配置属性方式-指定日志级别:** ``` feign: client: config: #想要调用的微服务名称 ali-pay-service: loggerLevel: full ``` **4-4. 全局配置-01-Java代码方式-指定日志级别** ``` @EnableFeignClients(defaultConfiguration = UserCenterFeignConfiguration.class) ``` **4-5. 全局配置-02-配置属性方式-指定日志级别** ``` feign: client: config: #全局配置 default: loggerLevel: full ``` **4-6. 支持的配置项** ``` 1. 代码方式支持的配置项 ``` ![](https://img.kancloud.cn/9d/e0/9de0d516e93b651a1d91e5ab4a216603_713x372.png) ``` 2. 属性方式支持的配置项 ``` ![](https://img.kancloud.cn/df/6c/df6c83d5afa843d19c4ba7d5c3d57b33_746x434.png) **4-7. 日志级别配置最佳实践总结** ![](https://img.kancloud.cn/42/ea/42ea9daf80bffd228ac06cab60073472_830x368.png)![](https://img.kancloud.cn/0c/d3/0cd3e51f331c660900284b1ddbdafba1_817x413.png)![](https://img.kancloud.cn/e1/8d/e18d06aa7cedbb51316f9464ff7f3c51_787x333.png) # 5. 多参数请求构造 ``` 1. GET方法 /** * name: 请求服务的名称 */ @FeignClient(name = "ali-pay-service", configuration = UserCenterFeignConfiguration.class) public interface UserCenterFeginClient { @GetMapping("/query") public User get0(@SpringQueryMap User user); } 此时会报405的错误,status 405 reading UserFeignClient#get0(User); content: {"timestamp":1482676142940,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/get"} 由异常可知,尽管我们指定了GET方法,Feign依然会使用POST方法发送请求.于是导致了异常. 正确写法如下: 方法一[推荐] @FeignClient("ali-pay-service") public interface UserFeignClient { @GetMapping("/get") public User get0(@SpringQueryMap User user); } 方法二[推荐] @FeignClient(name = "ali-pay-service") public interface UserFeignClient { @RequestMapping(value = "/get", method = RequestMethod.GET) public User get1(@RequestParam("id") Long id, @RequestParam("username") String username); } 这是最为直观的方式,URL有几个参数,Feign接口中的方法就有几个参数。使用@RequestParam注解指定请求的参数是什么. 方法三[不推荐] 多参数的URL也可使用Map来构建。当目标URL参数非常多的时候,可使用这种方式简化Feign接口的编写。 @FeignClient(name = "ali-pay-service") public interface UserFeignClient { @RequestMapping(value = "/get", method = RequestMethod.GET) public User get2(@RequestParam Map<String, Object> map); } 在调用时,可使用类似以下的代码。 public User get(String username, String password) { HashMap<String, Object> map = Maps.newHashMap(); map.put("id", "1"); map.put("username", "张三"); return this.userFeignClient.get2(map); } 注意:这种方式不建议使用。主要是因为可读性不好,而且如果参数为空的时候会有一些问题,例如map.put("username", null); 会导致"ali-pay-service 服务接收到的username是 "" ,而不是null. ``` ``` 2. post方法 @FeignClient(name = "ali-pay-service") public interface UserFeignClient { @RequestMapping(value = "/post", method = RequestMethod.POST) public User post(@RequestBody User user); } ``` # 6. Feign脱离Ribbon使用 ``` 场景: 用feign调用的服务没有注册到nacos / eureka上,怎么实现? ``` ``` /** * name: 可以随便写,但必须有 */ @FeignClient(name = "baidu", url = "http://www.baidu.com") public interface TestBaiduFeignClient { @GetMapping("") String index(); } ``` # 7. RestTemplate 对比 Feign ![](https://img.kancloud.cn/a1/b1/a1b1066a5d807754ddc2f45ee344b9b2_796x258.png) # 8. Feign性能优化 ``` 1. 为feign配置连接池[提升15%左右] 以apache的httpClient为例(okhttp同理,需要自己指定版本) 第一步: 加依赖: compile ("io.github.openfeign:feign-httpclient") 第二步: 写配置 feign: httpclient: #让feign使用apache httpclient做请求,而不是默认的urlConnection enabled: true #feign的最大连接数 max-connections: 200 #feign单个路径的最大连接数 max-connections-per-route: 50 ``` ``` 2. 日志级别(默认不打印的, 建议生产环境设置成BASIC) ``` # 9. 常见问题总结 ``` 参考: https://www.imooc.com/article/289005 ```