公司要作系統間的互通,因此須要程序之間互相調用接口,這塊一直是其餘同事在作,可是今天一個新項目須要調用到其餘系統的接口,因此看了下他們的調用方法,發現都是傳統的httpclient調用,外面作了一層封裝,相似這樣:git
HttpGet httpGet = new HttpGet(url); HttpClient client = new DefaultHttpClient(); HttpResponse resp = client.execute(httpGet); HttpEntity entity = resp.getEntity(); String respContent = EntityUtils.toString(entity, "utf-8").trim(); httpGet.abort(); client.getConnectionManager().shutdown(); return respContent;
而後在調用的時候,大概是這樣:github
String urls = mapToUrl("");//這裏是組合URL的方法 String result = HttpClients.clientDoPost(urls);//這裏就是調用上面封裝的httpclient JSONObject json = JSONObject.parseObject(result);//解析返回值
這樣有什麼弊端呢?在我看來最大的一點就是,調用方法沒有語義化。
稍微解釋一下,這種方法調用寫在controller裏面,給其餘人員看到,首先會理解爲:spring
貌似看起來很清晰,其實否則,對整個項目不熟悉的人,徹底不知道這三行代碼作了哪些事情,作了具體哪些業務操做,只知道我調用了一次http請求。
因此,我決定對項目總體的結構進行改造,而後纔有了今天這篇文章。json
公司有不少項目,以前都是外包出去作的,各類語言各類框架的都有,自我入職以來,新的項目我都採用了springboot框架,同時,也讓同事使用了這個框架。
因此此次改造,我打算接入springcloud,它和springboot無縫銜接這種自然的優點必需要好好利用。可是還有一些其餘項目沒有用到springboot,考慮到這種接入cloud比較困難,因此繼續保留了httpclient的調用方式。而後設計出大體的結構:springboot
既然打算要接入,總要說下好處,否則不能讓別人信服,我大體列出來四個。服務器
接入簡單app
在springboot上接入springcloud並註冊eureka服務器,只須要簡單幾步,加幾個註解就能夠完成。
沒有顯式的IP負載均衡
一般httpclient調用須要指定 IP+context||域名+context 才能定位到某個服務器上的某個具體應用,而經過springcloud的eureka註冊中心,在調用時只需指定服務名稱,註冊中心會自動發現對應的具體服務。
自動負載均衡框架
普通的http後臺要作負載均衡,須要藉助Nginx或者Apache這樣的第三方proxy程序,而springcloud的fegin客戶端會自動完成負載操做,發現eureka註冊中心上全部可用的服務。
強語義化maven
fegin客戶端調用http方法只須要和被調用的方法有同樣的方法聲明,requestParam註解,只需定義一下接口,feginClient註解會自動幫你實現,這樣就能夠像調用本地方法同樣調用遠程接口了。
以前肯定了總體的結構,如今就要把實現具體化,首先要把springcloud的服務和普通的http服務聯繫在一塊兒,而後再具體到某個服務的調用。這裏畫了一個大體的圖例。
普通的http服務還使用httpclient調用,只是多封裝了一層語義化,這裏先不贅述了,下面說下springcloud服務化以及調用eureka和普通http接口的方法。
首先要啓動註冊中心,去springcloud的GitHub下載Eureka Sample註冊中心模板,而後修改配置,放到服務器上運行。
首先,要使一個springboot程序註冊爲eureka服務,要引入maven包(沒有使用maven管理項目的童鞋要本身導包了)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
加入dependentsManage管理版本
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR4</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
而後在controller上加上註解@EnableEurekaClient註解
@EnableEurekaClient @RestController public class TestController { }
而後在springbootApplication啓動類上要加上@EnableDiscoveryClient,@EnableFeignClients,使它擁有一個fegin客戶端的能力。這裏就不貼代碼了。
最後要修改springboot的配置文件application.yml,增長eureka服務器和自身應用名稱的配置
eureka: client: serviceUrl: defaultZone: http://ip:port/eureka/ spring: application: name: your-application-Name
這樣,你的原有的服務就被改形成springcloud微服務了。
fegin調用很簡單,只要在接口上加上@FeignClient(value = "應用名"),而後定義下調用的接口聲明,就能夠了
//原接口 @RequestMapping(value = "/hi",method = RequestMethod.GET) public String sayHiFromClientOne(@RequestParam(value = "name") String name){ return "hello "+name; } //fegin客戶端 @FeignClient(value = "sportsHealth") public interface TestfeginClient { @RequestMapping(value = "/hi",method = RequestMethod.GET) String sayHiFromClientOne(@RequestParam(value = "name") String name); }
這裏在httpclient基礎上封裝成語義化的調用。
//繼承fegin接口的方法 public interface TestHttpClient extends TestfeginClient { } //實現類 @Service public class TestHttpClientImpl implements TestHttpClient { @Override public ConcretObject sayHiFromClientOne(String name) { Map<String, String> map = new HashMap<>(); map.put("name",name); String urls=MapToUrl("ip"+"context", map); String result = HttpClients.clientDoPost(urls); ConcretObject ret= JSONObject.parseObject(result, ConcretObject .class); return ret; }
這樣調用起來就和fegin以及本地方法無二了
//先注入 @Autowired private TestFeginClient testFeginClient; @Autowired private TestHttpClient testHttpClient; //調用Fegin testFeginClient.sayHiFromClientOne("張三"); //調用Http testHttpClient.sayHiFromClientOne("李四");
雖然如今以及很簡單了,可是如今存在一些普通的http接口,以及有些http接口後面要註冊到eureka服務可是如今還沒接入的。爲了儘可能統一化調用,不在業務層裏httpclient,feginclient混亂調用,咱們創建一層facade層,統一化調用,先調用fegin客戶端,失敗後嘗試http調用(ps:這會產生一些性能開銷,對實時性要求很強的公司最好就別這樣作了,這裏是由於咱們的實時性並不強,能夠接受一點延遲,結合實際狀況使用的)
下面是簡單的sample:
//先繼承feginclient接口 public interface TestFacade extends TestFeginClient { } //實現facade @Service public class TestFacadeImpl implements TestFacade { //先注入 @Autowired private TestFeginClient testFeginClient; @Autowired private TestHttpClient testHttpClient; //實現接口方法 @Override public ConcretObject sayHiFromClientOne(String name) { ConcretObject obj; try { //調用feginclient obj= testFeginClient.sayHiFromClientOne(name); }catch (Exception e){ try { //調用httpclient obj= testHttpClient.sayHiFromClientOne(name); }catch (Exception e1){ //都調用失敗處理 obj= new ConcretObject (); obj.setCode("1"); obj.setMessage("調用失敗"); } } return obj; } }
以上就是個人初衷到設計思路到具體的實現,springcloud還有不少強大的成員:斷路器,路由,。。。目前尚未用上,固然,我也在學習過程當中,但願能和你們一塊兒交流,最後附上個人GitHub,歡迎給我star。