feign的知识
外部的应用(网站/app) 通过网关gateway调用微服务, 那么微服务之间又该如何调用呢? 一般来说是用 Spring 提供的 RestTemplate进行调用. 类似于 172.10.10.10/api/xx-service/hello 这种方式. 但显然这种方式非常不好, 原因是:
- 服务有可能有多个实例. 在之前的例子里我们用 orderApi部署了两个实例, 它们的端口是不一样的. 那么调用的时候写哪个服务?
- 很显然这样调用没有用上负载均衡特性.
所以我们必须把组件内部调用再封装一层接口, 通过调用这个接口, 不用管内部到底有几个微服务实例, 到底有几个实例可用. 这就是feign的作用.
消费者的概念
在术语中, 这样专门用于微服务之间调用的接口叫做消费者接口. 我个人不是很喜欢用这样的词, 众所周知软件行业喜欢造新词, 就记住这样的接口是用feign 实现, 并且用于微服务之间调用, 就可以了.
feign-demo工程解读
工程位于: https://gitee.com/xiaofeipapa/spring-cloud-demo
文件夹: feign-demo
增加orderApi的方法
在类里加上一个新方法, 表示是微服务之间的调用方法:
@RequestMapping(value="/internal_hello", method = RequestMethod.GET)
private String internalHello(){
return "我是 order service, 提供给其他微服务的方法, 端口为: " + serverPort;
}
增加新的orderApiClient 工程
如图:
里面有用feign 实现的一个接口:
package org.xiaofeipapa.feimall.orderApiClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* 作者: 小肥爬爬
* 简书: //www.greatytc.com/u/db796a501972
* gitee: https://gitee.com/xiaofeipapa
* 邮箱: imyunshi@163.com
*
* 您可以自由转载此博客文章, 恳请保留原链接, 谢谢!
**/
// value 对应服务注册的名字
@FeignClient(value = "order-api")
public interface OrderFeignClient {
// 对应服务中的方法名
@GetMapping("internal_hello")
String internalHello();
}
为什么要新建一个工程呢? 在实际的业务开发中, 如果A服务需要调用C服务, 为了解耦/不增加太多加载包/方便沟通 等种种原因, 通常我们会在中间加一个调用层, 作为一个独立的jar包而加载, 用图表示如下:
为什么是CA呢? 因为内部服务是C提供的, 当然C服务的团队成员最熟, 所以他们来维护接口更高效方便. (能者多劳大概就是这个意思吧)
修改userApi工程
在idea里配置
在idea 的组件依赖间配好, 让userApi 依赖 orderApiClient. 这涉及idea的使用, 不再赘述.
修改pom
在pom里加入:
<dependencies>
<dependency>
<groupId>org.xiaofeipapa.feimall</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>orderApiClient</artifactId>
</dependency>
</dependencies>
修改启动类
如下:
package org.xiaofeipapa.feimall.userApi;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
import java.util.stream.Collectors;
@EnableFeignClients(basePackages = {"org.xiaofeipapa.*"})
@SpringBootApplication
@EnableDiscoveryClient
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class UserApiApplication {
public static void main( String[] args )
{
SpringApplication.run(UserApiApplication.class, args);
}
/**
* 使用 openFeign的时候必须加入这个, 否则会报错: No qualifying bean of type 'org.springframework.boot.autoconfigure.http.HttpMessageConverters' available:
* @param converters
* @return
*/
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
}
如果 OrderFeignClient 类放在userApi工程, 那么它会直接被发现. 而现在是在一个独立的工程, 所以要加上扫描路径 backPackages = {xxx }
增加业务方法
在controller里增加:
@Resource
OrderFeignClient orderFeignClient;
@RequestMapping(value="/test_feign", method = RequestMethod.GET)
private String testFeign(){
String v1 = "我是 user service, 端口为: " + serverPort;
String result = ", 从order api 得到: " + orderFeignClient.internalHello();
return v1 + result;
}
测试
现在, 启动order api / user api / gateway 各个工程, 在浏览器敲入: http://localhost:10000/api/user/test_feign
你应该可以看到这样的结果:
这表示feign 调用已经成功了.
feign的其他知识
feign的一些配置信息在网上都可以找得到, 不再赘述. 而一些高级知识, 比如负载均衡, 和hystrix的融合, 会在以后再写.