好未来课件系统技术升级实践—引入OpenFeign

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导读:对于业务系统而言,系统的架构决定了系统的可扩展性,应用的技术的决定了开发的效率,是否能够快速迭代,是决定产品是否能够占领市场的一个很重要因素。很多公司在进行技术升级时,都会或多或少遇到一些问题,本文主要讲解老项目接入OpenFeign组件时重构的思想、遇到的问题、解决的方案,以及为什么要这样做,其他人遇到类似问题也可以做参考,需要了解OpenFeign API的同学可以去github官网。"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. 背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"课件系统构建初期正好是微服务概念阶段,当时还没有Spring Boot这套框架,我们内部自己搭建了一套前后端分离,微服务化的系统。根据开发人员的使用习惯,系统中存在两种http请求的方式:1. 用Apache HttpClient写了一个工具类封装了GET、POST等各种请求并覆盖了不同的使用场景, 2. 使用Spring自带的RestTemplate。较原生的东西都存在一个很大的优点:扩展方便,但同时也存在一个很大的缺点:应用时会书写大量的代码,不利于后期维护。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2020年来业务快速增长,面对层出不穷的客户需求,不单单为了目前的快速迭代,从系统可扩展性与稳定性考虑,从长远角度考虑,技术必须要做升级,引入OpenFeign就是计划之一。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. 为什么选用OpenFeign"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"面向接口编程"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"扩展性好"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"支持熔段与负载均衡"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"支持自定义序列化与反序列化机制"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"可以自己集成OkHttp, Apache HttpClient等"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"支持各种日志组件"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":1,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"很方便的注入拦截器"}]}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" ..."}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":3},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"Spring Cloud也用的OpenFeign"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. 落地过程"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"3.1 开始实践"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"因为此项目用的是Struts2+Spring的架构,所以直接引入"},{"type":"codeinline","content":[{"type":"text","text":"spring-cloud-starter-openfeign"}]},{"type":"text","text":"的方式行不通,同时未避免引入其它问题,也不能强上,所以要自己另找门路了。"}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"最开始按照官方demo重构了一个接口,抽象出来如下:"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" interface BankFeign {\n @RequestLine(\"POST \/account\/{id}\")\n Account getAccountInfo(@Param(\"id\") String id);\n }\n\n public class BankService {\n public void Service() {\n BankFeign bankFeign = Feign.builder().logger(BankFeign.class).logLevel(Logger.Level.FULL)\n .options(new Request.Options(2000, 5000))\n .encoder(new JacksonEncoder())\n .decoder(new JacksonDecoder())\n .target(BankFeign.class, \"https:\/\/api.examplebank.com\");\n Account account = bankFeign.getAccountInfo(\"1234\");\n }\n }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里有一个很明显的问题,每次请求其他服务都要new一个Builder,这明显是框架级别统一的配置不符合系统设计的原则,当代码写完,这种写法就被pass了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":2,"normalizeStart":2},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"把Builder当作bean注入"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":2,"normalizeStart":2},"content":[{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" @Bean\n public Feign.Builder getFeignBuilder(){\n Feign.Builder feignBuilder = Feign.builder().logger(new Slf4jLogger()).logLevel(Logger.Level.FULL)\n .options(new Request.Options(2000, 5000))\n .encoder(new JacksonEncoder())\n .decoder(new JacksonDecoder());\n return feignBuilder;\n }\n \n public void Service() {\n BankFeign bankFeign = feignBuilder.target(BankFeign.class, \"https:\/\/api.examplebank.com\");\n Account account = bankFeign.getAccountInfo(\"1234\");\n }"}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看似比较完美了,但是会造成频繁生成Feign接口代理类对象,同时会造成gc频繁,所以也不可取。参考下Spring Cloud,是以api接口的维度注入的bean,所以有了下面的方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":3,"normalizeStart":3},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"以接口维度注入"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":2,"normalizeStart":2},"content":[{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" @Bean\n public BankFeign getFeignBuilder(){\n Feign.Builder feignBuilder = Feign.builder().logger(new Slf4jLogger()).logLevel(Logger.Level.FULL)\n .options(new Request.Options(2000, 5000))\n .encoder(new JacksonEncoder())\n .decoder(new JacksonDecoder());\n return feignBuilder.target(BankFeign.class, \"https:\/\/api.examplebank.com\");\n }\n"}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章