前提介绍

  • Feign是SpringCloud中服务消费端的调用框架,通常与ribbon,hystrix等组合使用。

  • 由于遗留原因,某些项目中,整个系统并不是SpringCloud项目,甚至不是Spring项目,而使用者关注的重点仅仅是简化http调用代码的编写。

  • 如果采用httpclient或者okhttp这样相对较重的框架,对初学者来说编码量与学习曲线都会是一个挑战,而使用spring中RestTemplate,又没有配置化的解决方案,由此想到是否可以脱离Spring cloud,独立使用Feign。

内容简介

Feign使得 Java HTTP 客户端编写更方便。Feign 灵感来源于Retrofit、JAXRS-2.0和WebSocket。Feign最初是为了降低统一绑定Denominator到HTTP API的复杂度,不区分是否支持Restful。Feign旨在通过最少的资源和代码来实现和HTTP API的连接。通过可定制的解码器和错误处理,可以编写任意的HTTP API。

maven依赖

  <dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-core</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>
<dependency>
<groupId>io.github.lukehutch</groupId>
<artifactId>fast-classpath-scanner</artifactId>
<version>2.18.1</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.18.0</version>
</dependency>

定义配置类

RemoteService service = Feign.builder()
.options(new Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3))
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.target(RemoteService.class, "http://127.0.0.1:8085");
  • options方法指定连接超时时长及响应超时时长
  • retryer方法指定重试策略
  • target方法绑定接口与服务端地址。
  • 返回类型为绑定的接口类型。

自定义接口

随机定义一个远程调用的服务接口,并且声明相关的接口参数和请求地址。

通过@RequestLine指定HTTP协议及URL地址


public class User{
String userName;
} public interface RemoteService {
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("POST /users/list")
User getOwner(User user);
@RequestLine("POST /users/list2")
@Headers({
"Content-Type: application/json",
"Accept: application/json",
"request-token: {requestToken}",
"UserId: {userId}",
"UserName: {userName}"
})
public User getOwner(@RequestBody User user,
@Param("requestToken") String requestToken,
@Param("userId") Long userId,
@Param("userName") String userName);
}

服务提供者

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping(value="users")
public class UserController {
@RequestMapping(value="/list",method={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT})
@ResponseBody
public User list(@RequestBody User user) throws InterruptedException{
System.out.println(user.getUsername());
user.setId(100L);
user.setUsername(user.getUsername().toUpperCase());
return user;
}
}

调用

与调用本地方法相同的方式调用feign包装的接口,直接获取远程服务提供的返回值。

String result = service.getOwner(new User("scott"));

原生Feign的两个问题

  1. 原生Feign只能一次解析一个接口,生成对应的请求代理对象,如果一个包里有多个调用接口就要多次解析非常麻烦。

  2. Feign生成的调用代理只是一个普通对象,该如何注册到Spring中,以便于我们可以使用@Autowired随时注入。

解决方案:

  1. 针对多次解析的问题,可以通过指定扫描包路径,然后对包中的类依次解析。

  2. 实现BeanFactoryPostProcessor接口,扩展Spring容器功能。

定义一个注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignApi {
/**
* 调用的服务地址
* @return
*/
String serviceUrl();
}

生成Feign代理并注册到Spring实现类:

import feign.Feign;
import feign.Request;
import feign.Retryer;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.List; @Component
public class FeignClientRegister implements BeanFactoryPostProcessor{ //扫描的接口路径
private String scanPath="com.xxx.api"; @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
List<String> classes = scan(scanPath);
if(classes==null){
return ;
}
System.out.println(classes);
Feign.Builder builder = getFeignBuilder();
if(classes.size()>0){
for (String claz : classes) {
Class<?> targetClass = null;
try {
targetClass = Class.forName(claz);
String url=targetClass.getAnnotation(FeignApi.class).serviceUrl();
if(url.indexOf("http://")!=0){
url="http://"+url;
}
Object target = builder.target(targetClass, url);
beanFactory.registerSingleton(targetClass.getName(), target);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
} public Feign.Builder getFeignBuilder(){
Feign.Builder builder = Feign.builder()
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Request.Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3));
return builder;
} public List<String> scan(String path){
ScanResult result = new FastClasspathScanner(path).matchClassesWithAnnotation(FeignApi.class, (Class<?> aClass) -> {
}).scan();
if(result!=null){
return result.getNamesOfAllInterfaceClasses();
}
return null;
}
}
调用接口编写示例:
import com.xiaokong.core.base.Result;
import com.xiaokong.domain.DO.DeptRoom;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import com.xiaokong.register.FeignApi; import java.util.List; @FeignApi(serviceUrl = "http://localhost:8085")
public interface RoomApi {
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /room/selectById?id={id}")
Result<DeptRoom> selectById(@Param(value="id") String id);
@Headers({"Content-Type: application/json","Accept: application/json"})
@RequestLine("GET /room/test")
Result<List<DeptRoom>> selectList();
}
接口使用示例:
@Service
public class ServiceImpl{
//将接口注入要使用的bean中直接调用即可
@Autowired
private RoomApi roomApi;
@Test
public void demo(){
Result<DeptRoom> result = roomApi.selectById("1");
System.out.println(result);
}
}

注意事项:

  1. 如果接口返回的是一个复杂的嵌套对象,那么一定要明确的指定泛型,因为Feign在解析复杂对象的时候,需要通过反射获取接口返回对象内部的泛型类型才能正确使用Jackson解析。如果不明确的指明类型,Jackson会将json对象转换成一个LinkedHashMap类型。

  2. 如果你使用的是的Spring,又需要通过http调用别人的接口,都可以使用这个工具来简化调用与解析的操作。

【SpringCloud技术专题】「原生态Fegin」打开Fegin之RPC技术的开端,你会使用原生态的Fegin吗?(上)的更多相关文章

  1. 「黑科技」智能消毒防疫机器人 技术方案介绍-disinfection robot

    消毒机器人 小新防疫消杀机器人 - 自主导航全方位360°臭氧杀菌消毒机器人,采用臭氧无阻碍.无死角.遍布整个空间除菌:强力涡轮风机,30㎡室内空气循环6次/h,10分钟速效杀菌.除异味.自动转化为氧 ...

  2. 【转】具透 | 你可能不知道,iOS 10 有一个中国「特供」的联网权限功能

    9 月底,苹果正式在北京成立了苹果中国研发中心.近几年,我们也在每年更新的 iOS 系统中不断看到,苹果对中国市场的关照.从早前的九宫格输入法,到最近的骚扰电话拦截,都照顾了国内用户的需求. 在 iO ...

  3. 技术专题-PHP代码审计

    作者:坏蛋链接:https://zhuanlan.zhihu.com/p/24472674来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 一.前言 php代码审计如字面 ...

  4. 走进JavaWeb技术世界3:JDBC的进化与连接池技术

    走进JavaWeb技术世界3:JDBC的进化与连接池技术 转载公众号[码农翻身] 网络访问 随着 Oracle, Sybase, SQL Server ,DB2,  Mysql 等人陆陆续续住进数据库 ...

  5. 最适合新手入门的SpringCloud教程 6—Ribbon负载均衡「F版本」

    SpringCloud版本:Finchley.SR2 SpringBoot版本:2.0.3.RELEASE 源码地址:https://gitee.com/bingqilinpeishenme/Java ...

  6. LaTeX 有哪些「新手须知」的内容?

    孟晨 ,在 LaTeX 话题下写错 LaTeX 名字的,一律… 陈硕等 137 人赞同 这是个好问题,虽然提问提得很大.不是很好答,权当抛砖引玉了. 天字第一号原则:不要到网上抄代码,尤其是似懂非懂的 ...

  7. 下雨天,适合学「Spring Boot」

      北方的闷热,让不少小伙伴盼着下雨,前几天北京下了场大雨,杭州也紧跟这下了场雨,就在昨天原本还很闷热的天,突然就飘泼大雨了.今天也断断续续的下着小雨,一觉醒来已经是10点了.有句话说:懒惰是人的天性 ...

  8. 「Android 开发」入门笔记

    「Android 开发」入门笔记(界面编程篇) ------每日摘要------ DAY-1: 学习笔记: Android应用结构分析 界面编程与视图(View)组件 布局管理器 问题整理: Andr ...

  9. NLP领域的ImageNet时代到来:词嵌入「已死」,语言模型当立

    http://3g.163.com/all/article/DM995J240511AQHO.html 选自the Gradient 作者:Sebastian Ruder 机器之心编译 计算机视觉领域 ...

随机推荐

  1. 『动善时』JMeter基础 — 50、使用JMeter测试WebService接口

    目录 1.什么是WebService 2.WebService和SOAP的关系 3.什么是WSDL 4.测试WebService接口前的准备 (1)如何判断是WebService接口 (2)如何获取W ...

  2. Java安全之Weblogic内存马

    Java安全之Weblogic内存马 0x00 前言 发现网上大部分大部分weblogic工具都是基于RMI绑定实例回显,但这种方式有个弊端,在Weblogic JNDI树里面能将打入的RMI后门查看 ...

  3. gitla 报错 The project you were looking for could not be found or you don't have permission to view it.

    gitlab项目组下创建项目 $ git push -u git@192.168.101.129:/DrvOps/Dev_Test : 报错信息如下: remote: ================ ...

  4. 11、linux的目录结构

    11.1.查看磁盘的id: blkid 11.2.linux目录类似一个倒挂的树: / 是所有目录的顶点,目录磁盘和分区是没有关联的,因此/下不同的目录会对应不同的磁盘的不同的分区: linux中硬盘 ...

  5. vue elementui table 内按钮跳转页面

    vue : <el-table-column label="操作" v-if="isColumOperate"> <template slot ...

  6. 资源:docker离线安装包下载路径

    docker安装包下载路径: docker所有版本:https://download.docker.com/linux/static/stable/

  7. Mysql/Oracle/达梦中数据字典表

    在mysql中,数据字典表存放在information_schema库中,,对应的两张表,分别是TABLES,和COLUMNS. 在oracle中有表空间(即用户空间或者库)和模式的概念.模式和表空间 ...

  8. Sentinel流控与熔断

    参考: https://thinkwon.blog.csdn.net/article/details/103770879 项目结构 com.guo     ├── guo-sentinel       ...

  9. ROS2学习之旅(13)——创建ROS2 功能包

    一个功能包可以被认为是ROS2代码的容器.如果希望能够管理代码或与他人共享代码,那么需要将其组织在一个包中.通过包,可以发布ROS2工作,并允许其他人轻松地构建和使用它. 在ROS2中,创建功能包使用 ...

  10. ESP32-使用有刷直流电机笔记

    基于ESP-IDF4.1 1 /* 2 * 刷直流电动机控制示例,代码通过L298电机芯片测试 3 */ 4 5 #include <stdio.h> 6 7 #include " ...