通过接口实现JAVA和.NET互调用-JNInterface
使用C#编程多年,也十分感激微软在语言架构、语法糖、编辑器等方面给自己带来的便利。但因为最近工作中有接触到JAVA,渐渐地发现的确像大家说的那样,JAVA的生态很好,要找点什么几乎都有现成的,于是自然就想到了能不能用.NET来调用JAVA。
具了解,有个JNBridge的软件,可以"Bridge any Java with any .NET, anywhere",也许很好用,但是付费的,不喜欢。
又了解了一下其他的方法,都不怎么通用,支持不健全。
当然,通过WebService肯定是可以的,但是一直不喜欢webservice的臃肿。
于是就自己写了一个轻量级的小组件,java和.net各一个本版,都包含一个客户端和服务端,两个本版的客户端都可以与两个本版的服务端通信。
一句话概括来说就是:服务端监听客户端的请求,收到请求后会找到事先注册好的处理程序,处理后再返回客户端。(如果这个过程不了解,那么说明尊驾对HTTP也不了解,这段时间总有web开发者对我说http是有状态的,这一部分人应该也不理解...)
流程是很简单的,第一步就是定义消息体了,可以理解为HTTP协议定义的消息体,HTTP里有请求和应答,这里自然也有两个相似的东西,和实际生活中好多例子一样,比如有人问你"你吃饭了吗?",出于礼貌,不管你吃了没吃,当时心情如何,都应该回复人家。
这里我定义JNInvokeMessage和JNReturnMessage两个消息类(为了看起来清晰,贴出C#简化代码,java的基本是一样的)
JNInvokeMessage.cs
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
|
public
class
JNInvokeMessage
{
public
string
targetName {
get
;
set
; }
public
Dictionary<
string
,
object
> parameters;
public
JNInvokeMessage(
string
targetName)
{
this
.targetName = targetName;
}
public
JNInvokeMessage setParam(
string
key,
object
value)
{
lock
(
this
)
{
if
(parameters ==
null
) parameters =
new
Dictionary<
string
,
object
>();
}
parameters[key] = value;
return
this
;
}
public
object
getParam(
string
key)
{
if
(parameters ==
null
)
return
null
;
object
obj;
if
(parameters.TryGetValue(key,
out
obj))
{
return
obj;
}
return
null
;
}
}
|
JNReturnMessage.cs
1
2
3
4
5
6
7
8
|
public
class
JNReturnMessage
{
public
bool
ok {
get
;
set
; }
public
string
error {
get
;
set
; }
public
object
value {
get
;
set
; }
}
|
下一步就是定义一个接口契约了,在C#里,可以定义一个委托:
1
|
public
delegate
JNReturnMessage IJNInterface(JNInvokeMessage invokeMessage);
|
java里,没有委托,所以我们定义一个接口:
1
2
3
|
public
interface
IJNInterface {
JNReturnMessage invoke(JNInvokeMessage invokeMessage);
}
|
都是大同小异的东西,.NET委托其实是类。
接下来就是实现Client和Server了,基本都是一些通信逻辑,老套路了网上都有,就不帖代码了,主要就是Server里有个interfaces,来保存接口处理程序,处理程序相等于MVC的Controller里的Action。在.net里用Dictionary,java里用map:
1
|
private
Dictionary<
string
, IJNInterface> interfaces =
new
Dictionary<
string
, IJNInterface>();
|
1
|
private
Map<String, IJNInterface> interfaces =
new
HashMap<String, IJNInterface>();
|
字典的key就相当于url,唯一确定要调用的处理程序。
两边开启服务和客户端调用写法基本都是一样的,下面展示java开启服务,在.net客户端调用:
java service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
static
void
startServer()
throws
IOException {
JNServer server =
new
JNServer();
server.addInterface(
"test"
, invokeMessage -> {
System.out.println(invokeMessage.toJson());
JNReturnMessage returnMessage =
new
JNReturnMessage(
true
,
"hello .net"
);
return
returnMessage;
});
server.addInterface(
"home/index"
,
new
IJNInterface() {
@Override
public
JNReturnMessage invoke(JNInvokeMessage invokeMessage) {
System.out.println(invokeMessage.toJson());
JNReturnMessage returnMessage =
new
JNReturnMessage(
true
,
new
int
[]{
1
,
2
,
3
,
4
,
5
});
return
returnMessage;
}
});
server.start();
}
|
.net Client:
1
2
3
4
5
6
7
8
9
10
11
12
|
static
void
Main(
string
[] args)
{
//new Thread(new ThreadStart(startServer)).Start();
//Thread.Sleep(1000);
JNClient client =
new
JNClient();
JNInvokeMessage msg =
new
JNInvokeMessage(
"test"
);
var
ret = client.Invoke(msg);
Console.WriteLine(ret.toJson());
}
|
.net控制台显示,说明我们调用成功:
如果调用失败,ok为false,error是错误的描述。
把java程序或.net程序注册为服务,在windows上建议使用srvany.exe,简单好用,这里是SrvanyUI_1.0下载,下面是我测试用的java服务设置:
程序路径就是 java.exe,启动参数就是 -jar "服务jar包的路径"
注意:
消息格式是JSON,java里用了fastjson,.net里用了Newtonsoft.Json,所以如果在返回值或参数里用了复杂的对象或集合数组类的,反序列化处理应该是fastjson里的JSONObject和JSONArray,Newtonsoft.Json里的JObject和JArray。
下载:
源码:
http://git.oschina.net/loogn/Loogn.JNInterface.JAVA
http://git.oschina.net/loogn/Loogn.JNInterface.NET