1. 基本使用
1.1 安装
在调用方安装
maven方式安装
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
gradle方式安装
//OpenFeignimplementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
1.2 启动类增加注解@EnableFeignClients
@SpringBootApplication@EnableFeignClientspublic class ChannelApplication {public static void main(String[] args) {SpringApplication.run(ChannelApplication.class, args);}}
1.3 编写feign客户端
package com.springcloud.user_center.feignclients;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/6 01:06* @Project:epec* @Description:订单中心收藏模块Feign客户端* @Modified By:wangfan* @Version: V1.0*//*** value: 调用服务名称* path: 统一的路径前缀*/@FeignClient(value = "ORDER-CENTER", path = "/order")public interface OrderCenterCollectClientV3 {/*** 通过用户ID获取收藏的订单列表* @param userId* @return*/@GetMapping("/user/collect/list/{userId}")public String getOrderList(@PathVariable Integer userId);}
1.4 controller
import com.springcloud.user_center.feignclients.OrderCenterCollectClientV3;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;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/5 13:17* @Project:epec* @Description:TODO* @Modified By:wangfan* @Version: V1.0*/@RestControllerpublic class CollectController {@Autowiredprivate OrderCenterCollectClientV3 orderCenterCollectClientV3;/*** 获取用户收藏的订单列表版本v3* @param userId* @return*/@GetMapping("/collect/orders/v3/{userId}")public Object getCollectOrdersV3(@PathVariable("userId") Integer userId){String result = orderCenterCollectClientV3.getOrderList(userId);return result;}}
1.5 验证
打开浏览器. 输入URL: http://localhost:9000/collect/orders/v3/1
获取结果:
{“code”:”0000”,”msg”:”success”,”rersult”:[{“name”:”name1”,”id”:”100034”},{“name”:”name2”,”id”:”100035”},{“name”:”name3”,”id”:”100036”}]}
2. 进阶
2.1 Feign和OpenFeign的关系
Feign不在Spring生态内, 本身不支持Spring MVC的注解,它有一套自己的注解.
OpenFeign是Spring Cloud为Feign适应Spring生态开发的组件, 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
2.2 单独使用OpenFeign
编写feign客户端
import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/6 01:06* @Project:epec* @Description:订单中心收藏模块Feign客户端,单独使用OpenFeign.不集成Eureka* @Modified By:wangfan* @Version: V1.0*//*** value: 调用服务名称,随便指定一个* url: 具体地址*/@FeignClient(value = "MY-ORDER-CENTER", url = "http://localhost:10000/order")public interface OrderCenterCollectClientV4 {/*** 通过用户ID获取收藏的订单列表* @param userId* @return*/@GetMapping("/user/collect/list/{userId}")public String getOrderList(@PathVariable Integer userId);}
controller中使用
import com.springcloud.user_center.feignclients.OrderCenterCollectClientV4;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;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/5 13:17* @Project:epec* @Description:TODO* @Modified By:wangfan* @Version: V1.0*/@RestControllerpublic class CollectController {@Autowiredprivate OrderCenterCollectClientV4 orderCenterCollectClientV4;/*** 获取用户收藏的订单列表版本v4* @param userId* @return*/@GetMapping("/collect/orders/v4/{userId}")public Object getCollectOrdersV4(@PathVariable("userId") Integer userId){String result = orderCenterCollectClientV4.getOrderList(userId);return result;}}
验证
打开浏览器. 输入URL: http://localhost:9000/collect/orders/v3/1
获取结果:
{“code”:”0000”,”msg”:”success”,”rersult”:[{“name”:”name1”,”id”:”100034”},{“name”:”name2”,”id”:”100035”},{“name”:”name3”,”id”:”100036”}]}
2.3 项目里使用Feign
现有2个项目, 用户中心 user_center 和 订单中心 order_center. 现有一个业务需要查询用户收藏的订单列表. 因此需要从用户中心发起请求调用订单中心的服务.
在项目里真正的做法如下:
- 创建
- 编写order_center接口 ```java import org.springframework.web.bind.annotation.*;
/**
- @Author:壹心科技BCF项目组 wangfan
- @Date:Created in 2020/10/5 13:17
- @Project:epec
- @Description:TODO
- @Modified By:wangfan
@Version: V1.0 */ @RestController @RequestMapping(“/order”) public class OrderController {
/**
- 通过用户ID获取收藏的订单列表
- @param userId
- @return */ @GetMapping(“/user/collect/list/{userId}”) public String getOrderList(@PathVariable Integer userId){ //写死返回数据 return “{\”code\”:\”0000\”,\”msg\”:\”success\”,\”rersult\”:[{\”name\”:\”name1\”,\”id\”:\”100034\”},{\”name\”:\”name2\”,\”id\”:\”100035\”},{\”name\”:\”name3\”,\”id\”:\”100036\”}]}”; }
}
未完待续.....<a name="jTNSQ"></a>## 2.4 Feign注意事项1. 带参请求带参请求的话如果参数是在URL上, 必须加上`@RequestParam`注解```java/*** 通过用户ID获取收藏的订单列表* @param userId*/@GetMapping("/user/collect/list")public String getOrderList(@RequestParam("userId") Integer userId);
- Feign默认所有带参数的请求都是Post,想要使用指定的提交方式需引入依赖
<!-- 取消Feign默认所有带参数的请求都是Post的限制 --><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency>
指明提交方式://取消Feign默认所有带参数的请求都是Post的限制implementation 'io.github.openfeign:feign-httpclient'
/*** 通过用户ID获取收藏的订单列表* @param userId*/@RequestMapping(value = "/user/collect/list", method = RequestMethod.POST)@GetMapping("/user/collect/list")public String getOrderList(@RequestParam("userId") Integer userId);
2.5 feign拦截器
实现RequestInterceptor接口即可
import feign.RequestInterceptor;import feign.RequestTemplate;import org.springframework.stereotype.Component;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/6 23:36* @Project:epec* @Description:Feign拦截器* @Modified By:wangfan* @Version: V1.0*/@Componentpublic class FeignRequestInteceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {String feignTargetUrl = template.feignTarget().url();String path = template.path();System.out.println("feign拦截器"+FeignRequestInteceptor.class.getName()+" 打印, 请求url: " + feignTargetUrl+path);}}
配置文件增加配置
#指定Feign拦截器feign.client.config.service-valuation.request-interceptors[0]=com.springcloud.user_center.config.FeignRequestInteceptor
2.6 Feign开启调用权限
feign的默认配置类是:org.springframework.cloud.openfeign.FeignClientsConfiguration。默认定义了feign使用的编码器,解码器等。
允许使用@FeignClient的configuration的属性自定义Feign配置。自定义的配置优先级高于上面的FeignClientsConfiguration。
2.6.1 服务提供方(order_center)开启权限认证
加上Security即可, 参照Security配置即可, 点击跳转….
2.6.2 服务提供方增加权限配置类
继承WebSecurityConfigurerAdapter类, 并重写 configure(HttpSecurity http)方法
import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.config.http.SessionCreationPolicy;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/7 00:03* @Project:epec* @Description:开始Feign权限* @Modified By:wangfan* @Version: V1.0*/@Configuration@EnableWebSecuritypublic class SecurityConfigForFeign extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {// 关闭csrfhttp.csrf().disable();// 表示所有的访问都必须认证,认证处理后才可以正常进行http.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated();// 所有的rest服务一定要设置为无状态,以提升操作效率和性能http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);}}
再使用Feign调用order_center接口则报错, 401未认证.
user_center(服务调用方)使用Feign调用order_center(服务提供方)接口时, 增加权限认证的方式有2种
- 自定义配置
@Bean。 - 使用Feign拦截器。
2.6.3 user_center(服务调用方)增加自定义配置@Bean
```java import feign.auth.BasicAuthRequestInterceptor; import org.springframework.context.annotation.Bean;
/**
- @Author:壹心科技BCF项目组 wangfan
- @Date:Created in 2020/10/7 01:39
- @Project:epec
- @Description:Feign权限认证
- @Modified By:wangfan
@Version: V1.0 */ public class FeignAuthConfiguration {
//Feign权限认证Bean @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("wangfan", "123");
}
}
`@FeignClient` 加上`configuration`属性```java@FeignClient(value = "ORDER-CENTER", path = "/order", configuration = FeignAuthConfiguration.class)
OK,可以正常访问了。
如果在配置类上添加了@Configuration注解,并且该类在@``ComponentScan所扫描的包中,那么该类中的配置信息就会被所有的@FeignClient共享。
最佳实践是:不指定@Configuration注解(或者指定configuration,用注解忽略),而用手动指定配置类:
@FeignClient(name = "service-valuation",configuration = FeignAuthConfiguration.class)
2.6.4 user_center(服务调用方)使用Feign拦截器
import feign.RequestInterceptor;import feign.RequestTemplate;import org.springframework.stereotype.Component;import java.util.Base64;/*** @Author:壹心科技BCF项目组 wangfan* @Date:Created in 2020/10/6 23:36* @Project:epec* @Description:Feign调用其他模块接口认证拦截器* @Modified By:wangfan* @Version: V1.0*/@Componentpublic class FeignAuthRequestInteceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {template.header("Authorization", "Basic "+ Base64.getEncoder().encodeToString("wangfan:123".getBytes()));}}
配置文件指定拦截器位置
#指定Feign调用其他模块接口认证拦截器feign.client.config.service-valuation.request-interceptors[1]=learn.wangfan.springcloud.user_center.config.FeignAuthRequestInteceptor
2.7 Feign超时和重试
Feign默认支持Ribbon, Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制
#连接超时时间(ms)ribbon.ConnectTimeout=1000#业务逻辑超时时间(ms)ribbon.ReadTimeout=6000#同一台实例最大重试次数,不包括首次调用ribbon.MaxAutoRetries=1#重试负载均衡其他的实例最大重试次数,不包括首次调用ribbon.MaxAutoRetriesNextServer=1#是否所有操作都重试ribbon.OkToRetryOnAllOperations=false
使用ribbon重试机制,请求失败后,每个6秒会重新尝试
