不使用SpringBoot如何将原生Feign集成到Spring中来简化http调用
Github 使用示例(https://github.com/cky-thinker/spring-feign-client/blob/master/README.md)
在微服务架构中,如果使用得是SpringCloud,那么只需要集成SpringFeign就可以了,SpringFeign可以很友好的帮我们进行服务请求,对象解析等工作。
然而SpingCloud是依赖于SpringBoot的。在老的Spring项目中通常是没有集成SpringBoot,那么我们又该如何使用Feign组件进行调用呢?
这种情况下就只能使用原生Feign了,Feign使用手册:https://www.cnblogs.com/chenkeyu/p/9017996.html
使用原生Feign的两个问题:
一、原生Feign只能一次解析一个接口,生成对应的请求代理对象,如果一个包里有多个调用接口就要多次解析非常麻烦。
二、Feign生成的调用代理只是一个普通对象,该如何注册到Spring中,以便于我们可以使用@Autowired随时注入。
解决方案:
一、针对多次解析的问题,可以通过指定扫描包路径,然后对包中的类依次解析。使用工具:https://github.com/lukehutch/fast-classpath-scanner
二、实现BeanFactoryPostProcessor接口,扩展Spring容器功能。
具体代码:
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>
自定义注解:在扫描接口的过程中,可以通过一个自定义注解,来区分Feign接口并且指定调用的服务Url
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调用别人的接口,都可以使用这个工具来简化调用与解析的操作。
不使用SpringBoot如何将原生Feign集成到Spring中来简化http调用的更多相关文章
- quartz 集成到Spring中
记录一下,防止忘记. 需要的jar包,quartz-2.2.3.jar,commons-collection-3.1.jar,spring-context-support-4.3.4.RELEASE. ...
- SpringBoot 源码解析 (十)----- Spring Boot的核心能力 - 集成AOP
本篇主要集成Sping一个重要功能AOP 我们还是先回顾一下以前Spring中是如何使用AOP的,大家可以看看我这篇文章spring5 源码深度解析----- AOP的使用及AOP自定义标签 Spri ...
- SpringBoot系列(六)集成thymeleaf详解版
SpringBoot系列(六)集成thymeleaf详解版 1. thymeleaf简介 1. Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎. 2. Thymeleaf ...
- Springboot系列(七) 集成接口文档swagger,使用,测试
Springboot 配置接口文档swagger 往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配 ...
- 微服务通信之feign集成负载均衡
前言 书接上文,feign接口是如何注册到容器想必已然清楚,现在我们着重关心一个问题,feign调用服务的时候是如何抉择的?上一篇主要是从读源码的角度入手,后续将会逐步从软件构架方面进行剖析. 一.R ...
- CAS学习笔记五:SpringBoot自动/手动配置方式集成CAS单点登出
本文目标 基于SpringBoot + Maven 分别使用自动配置与手动配置过滤器方式实现CAS客户端登出及单点登出. 本文基于<CAS学习笔记三:SpringBoot自动/手动配置方式集成C ...
- 一键式Spring集成工具 Spring Boot
最近公司使用Spring boot进行开发,稍微了解一下,不过自我感觉把集中式配置applicate.properties搞明白,注解用过Spring MVC的boot绝对没问题的 比如拦截器:@As ...
- Redis篇之操作、lettuce客户端、Spring集成以及Spring Boot配置
Redis篇之操作.lettuce客户端.Spring集成以及Spring Boot配置 目录 一.Redis简介 1.1 数据结构的操作 1.2 重要概念分析 二.Redis客户端 2.1 简介 2 ...
- 【笔记】android sdk集成的eclipse中导入项目
android sdk集成的eclipse中导入项目 想要把旧的ADT项目,一模一样的导入进来,需要: 1.把项目放到,非当前ADT的workspace目录下: 2.从Project中Import,选 ...
随机推荐
- HTML Meta信息的优先级
一般来讲meta的信息都是不同维度的不会有冲突,不过下面两个有一定冲突: <meta name="renderer" content="webkit"&g ...
- 拖拽模块move1
刚开的博客,想着写点什么,以前写过拖拽函数,后来又学习了模块化,于是一直想把之前写的拖拽函数封成一个独立的模块,方便以后调用,说干就干,下面码代码... <script> var move ...
- python 正则表达式Re
Python正则表达式指南这篇文章很好,推荐阅读. 本文则是简单记录下我自己学习Re的笔记, 环境是python3.5. 1.简单的Re语法 ^ 匹配字符串开始位置. $ 匹配字符串结束位置. \b ...
- git进阶
一.刚提交的代码,发现需要微调一下 刚刚最新提交了一段代码,然后跟前端说,接口好了.过了2分钟,前端跟你说,哎,兄弟,那个金额能不能返回整数,不要小数点. 这个时候一般我们通常会修改一下之后,再提交一 ...
- Linux下gcc和g++的区别
首先编写了第一个C++程序,Hello,world! #include <iostream> using namespace std; void main() ...{ cout < ...
- Linux时间子系统之四:定时器的引擎:clock_event_device
早期的内核版本中,进程的调度基于一个称之为tick的时钟滴答,通常使用时钟中断来定时地产生tick信号,每次tick定时中断都会进行进程的统计和调度,并对tick进行计数,记录在一个jiffies变量 ...
- sql server 阻塞查询
在生产环境下,有时公司客服反映网页半天打不到,除了在浏览器按F12的Network响应来排查,确定web服务器无故障后.就需要检查数据库是否有出现阻塞 当时数据库的生产环境中主表数据量超过2000w, ...
- 架构选型之Nodejs与Java
前言: 身边越来越多的同事谈论Nodejs,谈其异步IO.事件回调.前后台统一一门语言,创业的朋友的第一个创业项目也选择了Nodejs,期望能够使用一种语言节省成本快速完成需求开发.与其他项目组的同事 ...
- app后端设计(10)--数据增量更新
在新浪微博的app中,从别的页面进入主页,在没有网络的情况下,首页中的已经收到的微博还是能显示的,这显然是把相关的数据存储在app本地. 使用数据的app本地存储,能减少网络的流量,同时极大提高了用户 ...
- 13.app后端为什么要用到消息队列
很多没有实际项目经验的小伙伴,对消息队列系统非常陌生,看着很多架构的介绍中,都提到消息队列.但是,不知道为什么要用消息队列?什么是消息队列?常见的消息队列产品有哪些? 通过阅读本文,帮你解开以上的疑惑 ...