Dubbo RPC plugin for Egg.js
$ npm i egg-dubbo-rpc --save
enable egg-dubbo-rpc plugin in ${app_root}/config/plugin.js:
// {app_root}/config/plugin.js
exports.dubboRpc = {
enable: true,
package: 'egg-dubbo-rpc',
};
// @example
exports.rpc = {
registry: {
address: '127.0.0.1:2181', // configure your real zk address
},
client: {
responseTimeout: 3000,
},
server: {
namespace: 'org.eggjs.rpc.test',
port: 12200,
maxIdleTime: 90 * 1000,
codecType: 'hessian2',
selfPublish: true,
version: '1.0.0',
group: 'DUBBO',
autoServe: true,
},
};
all configuations is under rpc
property
- registry (we use zookeeper as service registry in dubbo)
address:(required)
the zookeeper address
- client
responseTimeout:(optional)
number of milliseconds to wait for a response, if timeout will get an exception, the default value is 3000(ms)
- server
namespace:(required)
the default namespace to publish all servicesport:(optional)
the port which RPC server listening on, the default value is 12200maxIdleTime:(optional)
maximum idle time (in milliseconds) for a connectioncodecType:(optional)
the serialization type, default value is hessian2selfPublish:(optional)
if set to true (default), every worker process will listen on different portsversion:(optional)
the service version, default value is 1.0.0group:(optional)
the service group, default value is DUBBOautoServe:(optional)
if set to true (default), will launce Dubbo RPC server automatically
First, you need to put the JAR file (which contains the API interfaces) into {app_root}/assembly
folder.
And then you need to config $app_root/config/proxy.js
, which is a very important config file for RPC client, you should configure the services you needed, then executing the egg-rpc-generator tool to generate the proxy files.
Let's see a simple example of proxy.js. It declare a interface named: org.eggjs.dubbo.UserService
provided by dubbo
application
'use strict';
module.exports = {
group: 'HSF',
version: '1.0.0',
services: [{
appName: 'dubbo',
api: {
UserService: {
interfaceName: 'org.eggjs.dubbo.UserService',
},
},
dependency: [{
groupId: 'eggjs',
artifactId: 'dubbo-demo-api',
version: '1.0-SNAPSHOT',
}],
}],
};
details as follows:
version:(optional)
service version, the global configgroup:(optional)
service grouperrorAsNull:(optional)
if set true, we are returning null instead of throwing an exception while error appearsservices:(required)
RPC services configuationappName:(required)
the name of RPC providerapi:(required)
API detailsinterfaceName:(required)
interface nameversion:(optional)
service version, it will overwrite the global onegroup:(optional)
service group, it will overwrite the global one
dependency:(required)
like Maven pom configgroupId:(required)
uniquely identifies your project across all projectsartifactId:(required)
the name of the jar without versionversion:(required)
the jar version
Run egg-rpc-generator to generate the proxy files. After running success, it will generate all proxy files under ${app_root}/app/proxy
install egg-rpc-generator
$ npm i egg-rpc-generator --save-dev
add rpc command into scripts of package.json
{
"scripts": {
"rpc": "egg-rpc-generator"
},
}
execute the rpc command
$ npm run rpc
You can call the Dubbo RPC service by using ctx.proxy.proxyName
. The proxyName is key value of api object you configure in proxy.js. In our example, it's UserService
, and proxyName using lower camelcase, so it's ctx.proxy.userService
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
const result = await ctx.proxy.userService.echoUser({
id: 123456,
name: 'gxcsoccer',
address: 'Space C',
salary: 100000000,
});
ctx.body = result;
}
}
module.exports = HomeController;
you can use app.mockProxy
to mock the RPC interface
'use strict';
const mm = require('egg-mock');
const assert = require('assert');
describe('test/mock.test.js', () => {
let app;
before(async function() {
app = mm.app({
baseDir: 'apps/mock',
});
await app.ready();
});
afterEach(mm.restore);
after(async function() {
await app.close();
});
it('should app.mockProxy ok', async function() {
app.mockProxy('DemoService', 'sayHello', async function(name) {
return 'hello ' + name + ' from mock';
});
const ctx = app.createAnonymousContext();
const res = await ctx.proxy.demoService.sayHello('gxcsoccer');
assert(res === 'hello gxcsoccer from mock');
});
});
As above, you can call remote service as a local method.
create a JAR file that contains the API interface
Put your implementation code under ${app_root}/app/rpc
folder
// ${app_root}/app/rpc/UserService.js
exports.echoUser = async function(user) {
return user;
};
exports.interfaceName = 'org.eggjs.dubbo.UserService';
exports.version = '1.0.0';
exports.group = 'DUBBO';
'use strict';
const mm = require('egg-mock');
describe('test/index.test.js', () => {
let app;
before(async function() {
app = mm.app({
baseDir: 'apps/rpcserver',
});
await app.ready();
});
after(async function() {
await app.close();
});
it('should invoke HelloService', done => {
app.rpcRequest('org.eggjs.dubbo.UserService')
.invoke('echoUser')
.send([{
id: 123456,
name: 'gxcsoccer',
address: 'Space C',
salary: 100000000,
}])
.expect({
id: 123456,
name: 'gxcsoccer',
address: 'Space C',
salary: 100000000,
}, done);
});
});
For more details of app.rpcRequest, you can refer to this acticle
- RPC in Node.js Part One
- RPC in Node.js Part Two
- Cross-Language Interoperability between Egg.js & Dubbo
- Custom Service Discovery in Egg.js
- RPC Proxy Configuration in Egg.js
- RPC Unittest in Egg.js
Please open an issue here.