赞
踩
在Spring Cloud中,使用Feign非常简单——只需创建接口,并在接口上添加注解即可。 Feign支持多种注解,例如Feign自带的注解或者JAXRS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便
①:Ribbon+RestTemplate进行微服务调用 模式 ResponseEntity responseEntity = restTemplate.getForEntity("http://order-service/order/queryOrdersByUserId/"+userId,List.class);
- Ribbon进行调用
- @Bean
- @LoadBalanced
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
缺点:
ResponseEntity responseEntity = restTemplate.getForEntity("http://orderservice/order/queryOrdersByUserId/"+userId,List.class); ①:我们不难发现,我们构建上诉的URL 是比较简单的,假如我们业务系统十分复杂,类似如下节点 https://www.baidu.com/s? wd=asf&rsv_spt=1&rsv_iqid=0xa25bbeba000047fd&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=3&rsv_sug1=2&rsv_sug7=100&rsv_sug2=0&inputT=328&rsv_sug4=328 那么我们构建这个请求的URL是不是很复杂,若我们请求的参数有可能变动,那么是否这个URL是不是很复 杂
②: 如果系统业务非常复杂,而你是一个新人,当你看到这行代码,恐怕很难一眼看出其用途是什么!此时,你 很可能需要寻求老同事的帮助(往往是这行代码的作者,哈哈哈,可万一离职了呢?),或者查阅该目标地 址对应的文档(文档常常还和代码不匹配),才能清晰了解这行代码背后的含义!否则,你只能陷入蛋疼的 境地!
1.3.1)我们采取开发中常用的套路 定义一个03-ms-alibaba-feign-api工程
①:第一步,引入依赖
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring‐cloud‐starter‐openfeign</artifactId>
- </dependency>
②:第二步:修改打包方式(因为该工程式一个普通的jar 不需要打可执行的jar)
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven‐jar‐plugin</artifactId>
- </plugin>
- </plugins>
- </build>
第三步:编写声明式接口
- @FeignClient(name = "product‐center")
- public interface ProductCenterFeignApi {
-
- /**
- * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
- * @param productNo
- * @return
- */
- @RequestMapping("/selectProductInfoById/{productNo}")
- ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
- }
1.3.2)调用者工程03-ms-alibaba-feign-order
第一步:引入依赖包 03-ms-alibaba-feign-api
- <dependency>
- <groupId>com.tuling</groupId>
- <artifactId>03‐ms‐alibaba‐feign‐api</artifactId>
- <version>0.0.1‐SNAPSHOT</version>
- </dependency>
第二步: 开启注解加入 @EnableFeignClients
- @SpringBootApplication
- @EnableDiscoveryClient
- @EnableFeignClients
- public class MsAlibabaFeignOrderApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(Tulingvip03MsAlibabaFeignOrderApplication.class, args);
- }
- }
第三步:调用方式(像调用本地方式一样调用远程服务)
- @Autowired
- private ProductCenterFeignApi productCenterFeignApi;
-
- ProductInfo productInfo = productCenterFeignApi.selectProductInfoById(orderNo);
1.3.3)我们服务提供者ms-alibaba-feign-product 的controller 需要实现我们的productCenterFeignApi接口,防止修 改(比如我们的productCenterFeignApi修改了,若没有实现该接口,服务提供者感知不到)
第一步:引入依赖 ms-alibaba-feign-api
第二步:我们的ProductInfoController实现productCenterFeignApi接口
- @RestController
- public class ProductInfoController implements ProductCenterFeignApi
①: 我们在03-ms-alibaba-feign-api工程中添加Feign的自定义配置
- /**
- * 这个类上千万不要添加@Configuration,不然会被作为全局配置文件共享
- *
- */
- public class ProductCenterFeignConfig {
-
- @Bean
- public Logger.Level level() {
- //return Logger.Level.FULL;
- return Logger.Level.BASIC;
- }
- }
-
- @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
- public interface ProductCenterFeignApi {
-
- /**
- * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
- * @param productNo
- * @return
- */
- @RequestMapping("/selectProductInfoById/{productNo}")
- ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
- }
②:针对调用端工程03-ms-alibaba-customcfg-feign-order针对日志com.demo.feignapi 包下的日志级 别必须调整为DEBUG级别的 不然是不会打印日志的
- logging:
- level:
- com:
- demo:
- feignapi: debug
ProductCenterFeignApi 不用指定configuration的选项
- @FeignClient(name = "product‐center")
- public interface ProductCenterFeignApi {
-
- /**
- * 声明式接口,远程调用http://product‐center/selectProductInfoById/{productNo}
- * @param productNo
- * @return
- */
- @RequestMapping("/selectProductInfoById/{productNo}")
- ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
- }
在调用方:03-ms-alibaba-customcfg-feign-order 通过feign:client:config:微服务名称:loggerLevel: 日志级别来指定
- logging:
- level:
- com:
- demo:
- feignapi: debug
- feign:
- client:
- config:
- product‐center:
- loggerLevel: full
根据自动装配我们FeignClients的配置中的默认锲约是springmvc(也就是说支持SpingMvc注解)
- @Bean
- @ConditionalOnMissingBean
- public Contract feignContract(ConversionService feignConversionService) {
- return new SpringMvcContract(this.parameterProcessors, feignConversionService);
- }
-
- 所以我们在FeignClient上可以使用Mvc的注解
- @RequestMapping("/selectProductInfoById/{productNo}")
- ProductInfo selectProductInfoById(@PathVariable("productNo") String productNo);
现在我们需要想使用Feign的原生注解来标识方法需要修改锲约
-
- public class ProductCenterFeignConfig{
- /**
- * 根据SpringBoot自动装配FeignClientsConfiguration 的FeignClient的契约是SpringMvc
- *
- 通过修改契约为默认的Feign的锲约,那么就可以使用默认的注解
- * @return
- */
- @Bean
- public Contract feiContract() {
- return new Contract.Default();
- }
- }
-
-
-
FeignClient类ProductCenterFeignApi使用Feign原生的注解
- @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
- public interface ProductCenterFeignApi {
- /**
- * 修改锲约为Feign的 那么就可以使用默认的注解
- * @param productNo
- * @return
- */
- @RequestLine("GET /selectProductInfoById/{productNo}")
- ProductInfo selectProductInfoById(@Param("productNo") String productNo);
- }
- public class MyRequestInterceptor implements RequestInterceptor {
- @Override
- public void apply(RequestTemplate template) {
- template.header("token", UUID.randomUUID().toString());
- }
- }
-
- public class ProductCenterFeignConfig {
- @Bean
- public RequestInterceptor requestInterceptor() {
- return new MyRequestInterceptor();
- }
-
- }
-
-
- @FeignClient(name = "product‐center",configuration = ProductCenterFeignConfig.class)
- //@FeignClient(name = "product‐center")
- public interface ProductCenterFeignApi {
- @RequestLine("GET /getToken4Header")
- String getToken4Header(@RequestHeader("token") String token);
- }
服务提供者
- @RestController
- @Slf4j
- public class ProductInfoController implements ProductCenterFeignApi {
-
- @RequestMapping("/getToken4Header")
- public String getToken4Header(@RequestHeader("token") String token) {
- log.info("token:{}",token);
- return token;
- }
- }
第一步:开启连接池配置
- feign:
- client:
- config:
- product-center:
- loggerLevel: full
- contract: feign.Contract.Default
- httpclient:
- #让feign底层使用HttpClient去调用
- enabled: true
- max‐connections: 200 #最大连接数
- max‐connections‐per‐route: 50 #为每个url请求设置最大连接数
第二步:调整Feign的日志级别(强烈推荐使用Basic级别的)
2.5)Feign的生产实践 (以Feign的超时说了算) 问题
①:Feign的底层用的是Ribbon,那么我们怎么配置超时时间
服务提供方模拟耗时 睡眠3S
- 配置这个 ribbon肯定会超时
- ribbon:
- connectTimeout: 2000
- readTimeout: 2000
-
- (Feign不会超时)
- feign:
- client:
- config:
- default:
- connectTimeout: 5000
- readTimeout: 5000
正好调用是3S 说明以Feign的超时说了算
这种配置 Feign超时了
- ribbon:
- connectTimeout: 5000
- readTimeout: 5000
- http:
- client:
- enabled: true
- feign:
- client:
- config:
- default:
- connectTimeout: 2000
- readTimeout: 2000
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。