好未來課件系統技術升級實踐—引入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}}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章