傳統Http服務與SpringCloud微服務的整合

原由

公司要作系統間的互通,因此須要程序之間互相調用接口,這塊一直是其餘同事在作,可是今天一個新項目須要調用到其餘系統的接口,因此看了下他們的調用方法,發現都是傳統的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

  • 先組合一下URL和參數
  • 而後發起一個http請求
  • 最後解析http的response

貌似看起來很清晰,其實否則,對整個項目不熟悉的人,徹底不知道這三行代碼作了哪些事情,作了具體哪些業務操做,只知道我調用了一次http請求。
因此,我決定對項目總體的結構進行改造,而後纔有了今天這篇文章。json

總體結構設計

公司有不少項目,以前都是外包出去作的,各類語言各類框架的都有,自我入職以來,新的項目我都採用了springboot框架,同時,也讓同事使用了這個框架。
因此此次改造,我打算接入springcloud,它和springboot無縫銜接這種自然的優點必需要好好利用。可是還有一些其餘項目沒有用到springboot,考慮到這種接入cloud比較困難,因此繼續保留了httpclient的調用方式。而後設計出大體的結構:springboot

clipboard.png

優點對比

既然打算要接入,總要說下好處,否則不能讓別人信服,我大體列出來四個。服務器

  • 接入簡單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服務聯繫在一塊兒,而後再具體到某個服務的調用。這裏畫了一個大體的圖例。

clipboard.png

普通的http服務還使用httpclient調用,只是多封裝了一層語義化,這裏先不贅述了,下面說下springcloud服務化以及調用eureka和普通http接口的方法。

註冊中心

首先要啓動註冊中心,去springcloud的GitHub下載Eureka Sample註冊中心模板,而後修改配置,放到服務器上運行。

註冊eureka服務

首先,要使一個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調用

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);
}

Http調用

這裏在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("李四");

Facade Service

雖然如今以及很簡單了,可是如今存在一些普通的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。

相關文章
相關標籤/搜索