最近准备将公司的一个核心业务系统用 Java
进行重构,大半年没写 Java
,JDK
都更新到 14 了,考虑到稳定性等问题最终仍是选择的 JDK11
。java
在总体架构选型时,因为是一个全新的系统,因此没有历史包袱,同时团队中也有多位大牛坐镇,所以咱们的选项便大胆起来。git
最终结果就是直接一把梭,直接上将来的大趋势:Service Mesh
,直接把什么 SpringCloud
、Dubbo
这类分布式框架所有干掉。github
本次的重点不是讨论 Service Mesh
是什么、能解决什么问题、为何选择它,毕竟我也在学习阶段,啥时候整明白线上也稳定了再和你们来交流。spring
既然方向定了就开始实际撸码了,不过刚一开始就验证了”理想很丰满、现实很骨感“;markdown
因为咱们去掉了 SpringCloud
和 Dubbo
这类框架,服务的注册、发现、负载均衡等需求所有都下沉到 Service Mesh
中提供了。架构
但对于开发来讲依然但愿能够调用本地方法的方式来调用远程服务,这在 SpringCloud
这类框架中是很容易实现的,框架自己就有很好的支持。app
回到咱们这个场景,需求其实很简单,就是想达到 SpringCloud
中的 Feign
这样的声明式+注解的方式调用。负载均衡
@Autowired private StoreClient client ; Store store = client.update(1, store) 复制代码
使用 spring-cloud-openfeign
这个包其实就能实现上述的需求了,但这样会引入一些咱们根本不会使用的 SpringCloud
的相关依赖,让人感受”不干净了“;同时也和 Service Mesh
的理念相反,其中的一大目的就是要下降这类框架的侵入性。框架
其实 spring-cloud-openfeign
的核心就是 Feign,自己它也是能够开箱即用的,因此便尝试看 Feign
本身是否支持这样的用法。分布式
经过官方文档能够得知:是能够定义接口的形式来调用远程接口的,但它本质上是不依赖其余库即可以使用,因此它自己是没有和 Spring
整合也是合情合理,但也就形成了没有现成库可供咱们使用。
咱们天然是不想写上图红框处的代码的,但愿全部接口直接注入就可使用。
所以结合以上的需求便有了这个库 feign-plus
它的使用流程其实就是翻版的 spring-cloud-openfeign
:
@FeignPlusClient(name = "github", url = "${github.url}") public interface Github { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<GitHubRes> contributors(@Param("owner") String owner, @Param("repo") String repo); } 复制代码
在 SpringBoot
入口进行扫描:
@SpringBootApplication @EnableFeignPlusClients(basePackages = "top.crossoverjie.feign.test") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } 复制代码
在 Spring
上下文中直接注入使用:
@Autowired private Github github ; List<GitHubRes> contributors = github.contributors("crossoverJie", "feign-plus"); logger.info("contributors={}", new Gson().toJson(contributors)); 复制代码
因此当咱们须要调用一些外部第三方接口时(好比支付宝、外部 OpenAPI)即可相似于这样定义一个接口,把全部 HTTP 请求的细节屏蔽掉。
固然也适合公司内部之间的服务调用,和我们之前写 SpringCloud
或 Dubbo
时相似;服务提供方提供一个 Client
包,消费方直接依赖即可以调用。其余的负载均衡、容错之类的由 Service Mesh
替咱们完成。
对于内部接口,也能够加上 @RequestMapping("/path")
注解:
在请求时便会在 url 后拼接上 /order
,这样在配置 feign.order.service.url
时只须要填入服务提供方的域名或 IP 便可。
feign-plus
也支持切换具体的 httpclient,默认是 okhttp3
,经过如下配置即可更改。
# default(okhttp3)
feign.httpclient=http2Client
复制代码
固然也有其余相关配置:
feign.plus.max-idle-connections = 520
feign.plus.connect-timeout = 11000
feign.plus.read-timeout = 12000
复制代码
最后简单聊聊是如何完成的吧,其实本质上就是 spring-cloud-openfeign
的浓缩版。
其中最为核心的即是 top.crossoverjie.feign.plus.factory.FeignPlusBeanFactory
类。
该类实现了 org.springframework.beans.factory.FactoryBean
接口,并重写了 getObject()
方法返回一个对象。
这段代码是否是似曾相识,其实就是
Feign
的官方demo
。
这里所返回的对象其实就是咱们定义的接口的代理对象,而这个对象自己则是 Feign
,因此再往里说:咱们的 http
请求编解码、发起请求等逻辑又被这个 feign
对象所代理了。
这个 HardCodedTarget
则是 Feign
内部用于代理最终请求的对象。
有一个小难受的地方:这样的本身定义 Bean 而后注入对象 Idea 是识别不了的,认为当前上下文没有该 Bean,可是 spring-cloud-openfeign 却能够识别。
因为 Feign
支持多个客户端,因此这里的客户端能够经过配置文件动态指定。
利用 SpringBoot
提供的 @ConditionalOnExpression
注解能够根据配置动态的选择使用哪一个 httpclient
,也就是动态选择生成哪一个 Bean
。
这个库的逻辑很是简单,本质上就是封装了 Feign
并提供了 SpringBoot
的支持,欢迎有相似需求的朋友下载使用。
feign-plus
源码:github.com/crossoverJi…
你的点赞与分享是对我最大的支持