White's Studio.

Node.js通过 dubbo2.js 调用 java

2019/03/25 Share

1. Dubbo 是啥?

Dubbo 是一个由阿里开源的 RPC 框架。

简单说下RPC框架的背景。

From dubbo.apache.org

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

2. 使用 Dubbo 实现 Java 互调

​ 首先我们可以先尝试下同语言下的 Dubbo 调用,从容易开始。

​ 可以参考下 dubbo 官方文档 [http://dubbo.apache.org/zh-cn/docs/user/quick-start.html]

​ 这边简单尝试下,主要有两步

  1. 首先建立一个服务提供方, 也就是上图 Provider 的角色

  2. 接下来建立一个服务消费者, 也如同上图的 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
// TestProviderService.java

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
// 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注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 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的包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--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里面

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
// TestProviderService.java
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
// 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 的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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 对应的接口的。所以也是要引入跟服务端的那几个包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--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.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}


// 实例化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就可以使用

如下

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

CATALOG
  1. 1. 1. Dubbo 是啥?
  2. 2. 2. 使用 Dubbo 实现 Java 互调
    1. 2.1. 服务提供方建立 Provider
    2. 2.2. 服务消费者Consumer
  3. 3. 3. Node.js 如何通过 Dubbo 调用 Java
  4. 4. 4. Node.js 通过接口调用 Java 与 通过 Dubbo 调用 Java 的对比
    1. 4.0.1. 其他: