Node.js通過Dubbo2.js呼叫Java
Dubbo 是一個由阿里開源的 RPC 框架。
簡單說下RPC框架的背景。

Dubbo 是一種 RPC 框架,應用在分散式服務。

2. 使用 Dubbo 實現 Java 互調
首先我們可以先嚐試下同語言下的 Dubbo 呼叫,從容易開始。
可以參考下 dubbo 官方文件 dubbo.apache.org/zh-cn/docs/…
這邊簡單嘗試下,主要有兩步:
-
首先建立一個服務提供方, 也就是上圖 Provider 的角色;
-
接下來建立一個服務消費者, 也如同上圖的 Consumer 的角色;
服務提供方建立 Provider
1.0 使用Spring Boot 建立一個Spring 微服務(可以參考) yuchenzhen.github.io/2018/08/24/…
**1.1. 建立一個 Interface **
// TestProviderService.java package com.dubbo.learn.dubbo; public interface TestProviderService { String Hello (String who); } 複製程式碼
1.2 實現這個TestProviderServiceImpl
// TestProviderServiceImpl package com.dubbo.learn.dubbo.impl; import com.dubbo.learn.dubbo.TestProviderService; import com.alibaba.dubbo.config.annotation.Service; @Service(version="1.0.0") public class TestProviderServiceImpl implements TestProviderService{ public String Hello(String who) { return "Hello world ! Dear Programer " + who ; } } 複製程式碼
1.3 啟動程式主入口新增 @EnableDubbo
註解
// ProviderApplication.java package com.dubbo.learn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo; @SpringBootApplication @EnableDubbo public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } } 複製程式碼
為了引入這個 @EnableDubbo
註解,需要我們引入 com.alibaba
的包
<!--pom.xml--> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.5</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.11.1</version> </dependency> 複製程式碼
curator-framework
是dubbo所使用的訊息中心 Zookeeper
所需要的包
dubbo-spring-boot-starter
是 dubbo spring 的配置包
1.4 最後我們把dubbo 的啟動配置寫到 application.properties
裡面
# application.properties server.port = 8829 # dubbo.application.name=provider dubbo.registry.protocol=zookeeper dubbo.registry.address=zookeeper://127.0.0.1:2181 dubbo.scan.base-packages=com.dubboo.learn dubbo.protocol.name=dubbo dubbo.protocol.port=20880 dubbo.consumer.check=false 複製程式碼
整個專案結構如圖:

然後,啟動就好。
啟動之後,通過 dubbo Admin 網頁客戶端可以看見Provider的介面在 Regitry 裡面註冊成功。

服務消費者Consumer
1.0 使用Spring Boot 建立一個Spring 消費者的微服務
1.1 定義介面,這裡的介面路徑位置和包名最好一致 (不然要自己調整)
// TestProviderService.java package com.dubbo.learn.dubbo; public interface TestProviderService { String Hello (String who); } 複製程式碼
1.2 定義一個 Service呼叫該dubbo 介面
// TestConsumerService.java package com.dubbo.learn; import com.alibaba.dubbo.config.annotation.Reference; import com.dubbo.learn.dubbo.TestProviderService; import org.springframework.stereotype.Component; @Component public class TestConsumerService { @Reference(version = "1.0.0") TestProviderService testProviderService; public void consumer (String who) { String res = testProviderService.Hello(who); System.out.println("consumer : provider says " + res); } } 複製程式碼
在主程式函式呼叫該Service 的函式
// DubboConsumerApplication.java package com.dubbo.learn; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import com.dubbo.learn.TestConsumerService; @SpringBootApplication public class DubboConsumerApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(DubboConsumerApplication.class, args); TestConsumerService testConsumer = run.getBean(TestConsumerService.class); testConsumer.consumer("White"); } } 複製程式碼
@Reference
這個註解就是用來呼叫 dubbo 對應的介面的。所以也是要引入跟服務端的那幾個包
<!--pom.xml--> <dependency> <groupId>com.alibaba.boot</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>0.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.5</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.11.1</version> </dependency> 複製程式碼
1.3 最後我們把dubbo 的啟動配置寫到application.properties裡面
#application.properties server.port=8830 dubbo.application.name=consumer #註冊中心地址 dubbo.registry.address=zookeeper://127.0.0.1:2181 dubbo.scan.base-packages=com.dubboo.learn.dubbo dubbo.protocol.port=20880 複製程式碼
專案目錄結構如下:

啟動後效果如下:

3. Node.js 如何通過 Dubbo 呼叫 Java
Node 這邊通過 dubbo呼叫 Java 的 provider 的介面,我們嘗試呼叫了幾個包:sofa-rpc-node,node-zookeeper-dubbo,和dubbo2.js 。
其中 sofa-rpc-node 的對使用 egg.js框架的比較友好,node-zookeeper-dubbo 使用起來跟 sofa-rpc-node 差不多;但是有點麻煩的就是這兩個包都需要寫 proto3的介面定義。
而 dubbo2.js則比較方便,以下是使用 dubbo2.js 的示列
const { Dubbo, java, setting } = require('dubbo2.js') const interfaceName = 'com.dubbo.learn.dubbo.TestProviderService' const interfaceVersion = '1.0.0' const dubboSetting = setting.match( interfaceName, { version: interfaceVersion } ) const dubboService = dubbo => dubbo.proxyService({ dubboInterface: interfaceName, version: '1.0.0', methods: { Hello (who) { return [ java.String(who) ] } } }) const service = {dubboService} // 例項化Dubbo, 入參主要是名稱和 dubbo 介面的設定 const dubbo = new Dubbo({ application: {name: 'dubbo-node-test'}, register: '127.0.0.1:2181', dubboSetting, service }) module.exports = dubbo 複製程式碼
程式碼就是這麼簡單, 把 Java 服務裡面通過 dubbo 提供出來的介面(包括介面名,介面版本資訊,介面方法) 註冊一下。
得到Dubbo 例項之後,呼叫對應的 service就可以使用。
如下:
await dubbo.service.dubboService.Hello(who) 複製程式碼
我們簡單寫了一個介面:
const KoaRouter = require('koa-router') const dubbo = require('./dubbo') const router = new KoaRouter({prefix: '/api/v1'}) router.use('/') router.get('/testNodeDubbo', async (ctx, next) => { console.info(`[testNodeDubbo]:==:> start`) let {who} = ctx.request.query const res = await dubbo.service.dubboService.Hello(who) ctx.body = res }) module.exports = router 複製程式碼
呼叫結果:

這樣就完成了 node 作為消費者通過 dubbo 去呼叫 java 的介面了。
4. Node.js 通過介面呼叫 Java 與 通過 Dubbo 呼叫 Java 的對比

這邊嘗試使用了呼叫了同樣邏輯的 dubbo 和 http 介面, 對比了一下兩個實現的返回時間。
其中紅色的是 dubbo 介面, 藍色的是 http 介面。