1. Dubbo 是啥?
Dubbo 是一个由阿里开源的 RPC 框架。
简单说下RPC框架的背景。

Dubbo 是一种 RPC 框架,应用在分布式服务。

2. 使用 Dubbo 实现 Java 互调
    首先我们可以先尝试下同语言下的 Dubbo 调用,从容易开始。
    可以参考下 dubbo 官方文档 [http://dubbo.apache.org/zh-cn/docs/user/quick-start.html]
    这边简单尝试下,主要有两步
首先建立一个服务提供方, 也就是上图 Provider 的角色
 
接下来建立一个服务消费者, 也如同上图的 Consumer 的角色
 
服务提供方建立 Provider
1.0 使用Spring Boot 建立一个Spring 微服务 (可以参考)[https://yuchenzhen.github.io/2018/08/24/SpringBoot-IDE-initial/]
1.1 建立一个 Interface 
1 2 3 4 5 6 7
   | 
  package com.dubbo.learn.dubbo;
  public interface TestProviderService {     String Hello (String who); }
 
  | 
 
1.2 实现这个TestProviderServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12
   |  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注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   |  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的包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   |  <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里面
1 2 3 4 5 6 7 8 9 10
   | # 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 定义接口,这里的接口路径位置和包名最好一致 (不然要自己调整)
1 2 3 4 5 6
   |  package com.dubbo.learn.dubbo;
  public interface TestProviderService {     String Hello (String who); }
 
  | 
 
1.2 定义一个 Service调用该dubbo 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   |  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 的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   |  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 对应的接口的。所以也是要引入跟服务端的那几个包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   |  <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.4 最后我们把dubbo 的启动配置写到application.properties里面
1 2 3 4 5 6 7 8
   | #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 的示列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
   | 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}
 
 
  const dubbo = new Dubbo({   application: {name: 'dubbo-node-test'},   register: '127.0.0.1:2181',   dubboSetting,   service })
  module.exports = dubbo
  | 
 
代码就是这么简单, 把 Java 服务里面通过 dubbo 提供出来的接口(包括接口名,接口版本信息,接口方法) 注册一下
得到Dubbo 实例之后,调用对应的 service就可以使用
如下
1
   | await dubbo.service.dubboService.Hello(who)
   | 
 
本人简单写了一个接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | 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 接口。
其他:
项目地址: 
https://github.com/yuchenzhen/Java-dubbo-provider
https://github.com/yuchenzhen/Java-dubbo-client
https://github.com/yuchenzhen/node-dubbo2-consumer/tree/master