很遺憾,這不是一篇關於中間件理論或原理講解的文章,沒有高深晦澀的工作原理分析,文後也沒有令人驚歎的工程數字統計。本文以實際項目和代碼爲示例,一步一步演示如何以最低成本實現 Apache Dubbo 體系與 Spring Cloud 體系的互通,進而實現不同微服務體系的混合部署、遷移等,幫助您解決實際架構及業務問題。
背景與目標
如果你在微服務開發過程中正面臨以下一些業務場景需要解決,那麼這篇文章可以幫到您:
- 您已經有一套基於 Dubbo 構建的微服務應用,這時你需要將部分服務通過 REST HTTP 的形式(非接口、方法模式)發佈出去,供一些標準的 HTTP 端調用(如 Spring Cloud 客戶端),整個過程最好是不用改代碼,直接爲寫好的 Dubbo 服務加一些配置、註解就能實現。
- 您已經有一套基於 Spring Cloud 構建的微服務體系,而後又構建了一套 Dubbo 體系的微服務,你想兩套體系共存,因此現在兩邊都需要調用到對方發佈的服務。也就是 Dubbo 應用作爲消費方要調用到 Spring Cloud 發佈的 HTTP 接口,Dubbo 應用作爲提供方還能發佈 HTTP 接口給 Spring Cloud 調用。
- 出於一些歷史原因,你正規劃從一個微服務體系遷移到另外一個微服務體系,前提條件是要保證中間過程的平滑遷移。
對於以上幾個場景,我們都可以藉助 Dubbo3 內置的 REST 編程範式支持實現,這讓 Dubbo 既可以作爲消費方調用 HTTP 接口的服務,又可以作爲提供方對外發布 REST 風格的 HTTP 服務,同時整個編碼過程支持業界常用的 REST 編程範式(如 JAX-RS、Spring MVC 等),因此可以做到基本不改動任何代碼的情況下實現 Dubbo 與 Spring Cloud 體系的互相調用。
- 關於這一部分更多的設計與理論闡述請參見這裏的博客文章[1]
- 關於 Dubbo REST 的更多配置方式請參見 rest 使用參考手冊[2]
示例一:Dubbo 調用 Spring Cloud
在已經有一套 Spring Cloud 微服務體系的情況下,演示如何使用 Dubbo 調用 Spring Cloud 服務(包含自動的地址發現與協議傳輸)。在註冊中心方面,本示例使用 Nacos 作爲註冊中心,對於 Zookeeper、Consul 等兩種體系都支持的註冊中心同樣適用。
設想你已經有一套 Spring Cloud 的微服務體系,現在我們將引入 Dubbo 框架,讓 Dubbo 應用能夠正常的調用到 Spring Cloud 發佈的服務。本示例完整源碼請參見 samples/dubbo-call-sc[3]。
啓動 Spring Cloud Server
示例中 Spring Cloud 應用的結構如下:
應用配置文件如下:
server:
port: 8099
spring:
application:
name: spring-cloud-provider-for-dubbo
cloud:
nacos:
serverAddr: 127.0.0.1:8848 #註冊中心
以下是一個非常簡單的 Controller 定義,發佈了一個 /users/list/的 http 端點。
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/list")
public List<User> getUser() {
return Collections.singletonList(new User(1L, "spring cloud server"));
}
}
啓動 SpringCloudApplication,通過 cURL 或瀏覽器訪問 http://localhost:8099/users/list 可以測試應用啓動成功。
使用 Dubbo Client 調用服務
Dubbo client 也是一個標準的 Dubbo 應用,項目基本結構如下:
其中,一個比較關鍵的是如下接口定義(正常情況下,以下接口可以直接從原有的 Spring Cloud client 應用中原樣拷貝過來即可,無需做任何修改)。
如果之前沒有基於 OpenFeign 的 Spring Cloud 消費端應用,那麼就需要自行定義一個接口,此時不一定要使用 OpenFeign 註解,使用 Spring MVC 標準註解即可。
通過 DubboReference 註解將 UserServiceFeign 接口註冊爲 Dubbo 服務。
@DubboReference
private UserServiceFeign userService;
接下來,我們就可以用 Dubbo 標準的方式對服務發起調用了。
List<User> users = userService.users();
通過 DubboConsumerApplication 啓動 Dubbo 應用,驗證可以成功調用到 Spring Cloud 服務。
示例二:Spring Cloud 調用 Dubbo
在接下來的示例中,我們將展示如何將 Dubbo server 發佈的服務開放給 Spring Cloud client 調用。
示例的相關源碼在 samples/sc-call-dubbo[4]
啓動 Dubbo Server
Dubbo server 應用的代碼結構非常簡單,是一個典型的 Dubbo 應用。
相比於普通的 Dubbo 服務定義,我們要在接口上加上如下標準 Spring MVC 註解:
@RestController
@RequestMapping("/users")
public interface UserService {
@GetMapping(value = "/list")
List<User> getUsers();
}
除了以上註解之外,其他服務發佈等流程都一致,使用 DubboService 註解發佈服務即可:
@DubboService
public class UserServiceImpl implements UserService {
@Override
public List<User> getUsers() {
return Collections.singletonList(new User(1L, "Dubbo provider!"));
}
}
在服務配置上,特別注意我們需要將服務的協議配置爲 rest protocol: rest,地址發現模式使用 register-mode: instance:
dubbo:
registry:
address: nacos://127.0.0.1:8848
register-mode: instance
protocol:
name: rest
port: 8090
啓動 Dubbo 應用,此時訪問以下地址可以驗證服務運行正常:http://localhost:8090/users/list
使用 Spring Cloud 調用 Dubbo
使用 OpenFeign 開發一個標準的 Spring Cloud 應用,即可調用以上發佈的 Dubbo 服務,項目代碼結構如下:
其中,我們定義了一個 OpenFeign 接口,用於調用上面發佈的 Dubbo rest 服務。
@FeignClient(name = "dubbo-provider-for-spring-cloud")
public interface UserServiceFeign {
@RequestMapping(value = "/users/list", method = RequestMethod.GET)
List<User> getUsers();
}
定義以下 controller 作爲 OpenFeign 和 RestTemplate 測試入口:
public class UserController {
private final RestTemplate restTemplate;
private final UserServiceFeign userServiceFeign;
public UserController(RestTemplate restTemplate,
UserServiceFeign userServiceFeign) {
this.restTemplate = restTemplate;
this.userServiceFeign = userServiceFeign;
}
@RequestMapping("/rest/test1")
public String doRestAliveUsingEurekaAndRibbon() {
String url = "http://dubbo-provider-for-spring-cloud/users/list";
System.out.println("url: " + url);
return restTemplate.getForObject(url, String.class);
}
@RequestMapping("/rest/test2")
public List<User> doRestAliveUsingFeign() {
return userServiceFeign.getUsers();
}
}
根據以上 Controller 定義,我們可以分別訪問以下地址進行驗證:
- OpenFeign 方式:http://localhost:8099/dubbo/rest/test1
- RestTemplage 方式:http://localhost:8099/dubbo/rest/test2
爲 Dubbo Server 發佈更多的服務
我們可以利用 Dubbo 的多協議發佈機制,爲一些服務配置多協議發佈。接下來,我們就爲上面提到的 Dubbo server 服務增加 dubbo tcp 協議發佈,從而達到以下部署效果,讓這個 Dubbo 應用同時服務 Dubbo 微服務體系和 Spring Cloud 微服務體系。
爲了實現這個效果,我們只需要在配置中增加多協議配置即可:
dubbo:
protocols:
- id: rest
name: rest
port: 8090
- id: dubbo
name: dubbo
port: 20880
同時,服務註解中也配置爲多協議發佈:
@DubboService(protocol="rest,dubbo")
public class UserServiceImpl implements UserService {}
這樣,我們就成功的將 UserService 服務以 dubbo 和 rest 兩種協議發佈了出去(多端口多協議的方式),dubbo 協議爲 Dubbo 體系服務,rest 協議爲 Spring Cloud 體系服務。
注意:Dubbo 爲多協議發佈提供了單端口、多端口兩種方式,這樣的靈活性對於不同部署環境下的服務會有比較大的幫助。在確定您需要的多協議發佈方式前,請提仔細閱讀以下多協議配置 [5]文檔。
總結
基於 Dubbo 的 rest 編程範式、多協議發佈等特性,可以幫助你輕鬆的實現 Dubbo 服務的 http 協議發佈,讓後端服務基於 RPC 高效通信的同時,能夠更容易的與 http 服務體系打通,本示例通過 Dubbo 與 Spring Cloud 兩套體系的共存、互通示例非常清晰的演示了編碼過程。
此部分內容的正式版本將在 Dubbo 3.3.0 版本正式發佈,同時還包含 Triple 協議的重磅升級,敬請期待!
相關鏈接:
[1] 博客文章
[2] rest 使用參考手冊
https://cn.dubbo.apache.org/zh-cn/overview/reference/proposals/protocol-http/
[3] samples/dubbo-call-sc
[4] samples/sc-call-dubbo
[5] 多協議配置
作者:孫彩榮
點擊立即免費試用雲產品 開啓雲上實踐之旅!
本文爲阿里雲原創內容,未經允許不得轉載