少女祈祷中...

1.RMI

  • RMI:Remote Method Invocation 远程方法调用
  • 两个位于不同JVM虚拟机的Java程序互相请求访问

RMI的参数和返回值

  • (自动化) 传递远程对象(实现Remote接口)
    • 当一个对远程对象的引用从一个JVM传递到另一个JVM,该远程对象的发送者和接收者将持有同一个实体对象的引用。这个引用并非是一个内存位置,而是由网络地址和该远程对象的唯一标识符构成的。
      ###两个JVM拥有同一个对象###
  • (自动化) 传递可序列化对象(实现Serializable接口)
    • JVM中的一个对象经过序列化后的字节,通过网络,其副本传递到另一个JVM中,并重新还原为一个Java对象。
      ###每个JVM拥有自己的对象###
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//Client
Context namingContext = new InitialContext();

//开始查找RMI注册表上有哪些绑定的服务
Enumeration<NameClassPair> e = namingContext.list("rmi://127.0.0.1:8001/");
while (e.hasMoreElements())
System.out.println(e.nextElement().getName());

//获取某一个地址上的服务类
String url = "rmi://127.0.0.1:8001/warehouse1";
Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url);
/*
//接口类
public interface Warehouse extends Remote
{
double getPrice(String description) throws RemoteException;
}
*/

//输入参数 取得结果
String descr = "面包机";
double price = centralWarehouse.getPrice(descr);
System.out.println(descr + ": " + price);

//Server
System.out.println("产生服务器对象");
WarehouseImpl centralWarehouse = new WarehouseImpl();

System.out.println("将服务器对象绑定在8001端口,对外提供服务");
LocateRegistry.createRegistry(8001);//定义端口号
Naming.rebind("rmi://127.0.0.1:8001/warehouse1", centralWarehouse);

//实现类
public class WarehouseImpl extends UnicastRemoteObject implements Warehouse
{
private Map<String, Double> prices;

public WarehouseImpl() throws RemoteException
{
//物品列表
prices = new HashMap<>();
prices.put("面包机", 24.95);
prices.put("微波炉", 49.95);
}

public double getPrice(String description) throws RemoteException
{
Double price = prices.get(description);
return price == null ? 0 : price;
}
}
//接口类
public interface Warehouse extends Remote
{
double getPrice(String description) throws RemoteException;
}
  • RMI优点
    • 跨平台分布式对象调用
    • 完全对象支持
    • 安全策略
  • RMI缺点
    • 双方必须是Java语言实现
    • 不如消息传递协作方便

2.JNI

  • JNI,Java Native Interface
  • Java和本地C代码进行互操作
    • Java调用C程序完成一些需要快速计算的功能(常见,重点)
    • C调用Java程序(基于反射的方法)

基本步骤

  • 在Java类中声明一个本地方法,使用native函数
1
2
3
class HelloNative {
public static native void greeting();
}
  • 调用javac.exe编译,得到HelloNative.class
  • 调用javah.exe得到包含该方法(Java_HelloNative_greeting)的头文件HelloNative.h
  • 实现.c文件(对应HelloNative.h)
1
2
3
4
5
#include "HelloNative.h"

JNIEXPORT void JNICALL Java_HelloNative_greeting(JNIEnv* env, jclass cl) {
printf("Hello Native World\n");
}
  • 将.c和.h文件,整合为共享库(DLL)文件
  • 在Java类中,加载相应的共享库文件
1
2
3
4
HelloNative.greeting();
static {
System.loadLibrary("HelloNative"); //dll名字
}

3.Nashorn

  • 脚本引擎,ScriptEngine
    • Nashorn,JDK 8自带的JS解释器(JDK6/7是Rhino解释器)
1
ScriptEngine engine = new ScriptEngineManager().getEngineByName(“nashorn”)
  • 主要方法
    • eval,执行一段js脚本. eval(String str), eval(Reader reader)
    • put,设置一个变量
    • get,获取一个变量
    • createBindings, 创建一个Bindings
    • setBindings, 设置脚本变量使用的范围
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
36
//Test1
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");

engine.put("a", 100);
engine.put("b", 200);
engine.eval("var c = a+b");
String result = engine.get("c").toString();

System.out.println(result);
//Test2
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
SimpleBindings simpleBindings = new SimpleBindings(); // 传递参数到js
simpleBindings.put("a", 100);
simpleBindings.put("b", 200);

Object result = engine.eval("load('src/edu/ecnu/sum2.js')", simpleBindings);
/*
src/edu/ecnu/sum2.js
c = a + b;
*/
System.out.println(result);
//Test3
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
FileReader scriptFile = new FileReader("src/edu/ecnu/sum3.js");
/*
src/edu/ecnu/sum3.js
function sum(a, b)
{
return a + b;
}
*/
engine.eval(scriptFile);

Invocable in = (Invocable) engine;
String result = in.invokeFunction("sum",100,200).toString();
System.out.println(result);

JDK支持的脚本引擎工厂

引擎名字MIME类型文件扩展
Nashornnashorn,jstext/javascriptjs
Groovygroovygroovy
RenjinRenjintext/x-RR,r,S,s
SISC Schemesiscscheme,sisc

4.Jython

  • Jython是Python语言在Java平台的实现
  • Jython是在JVM上实现的Python,由Java编写
  • Jython将Python源码编译成JVM字节码,由JVM执行对应的字节码,因此能很好的与JVM集成
  • Jython并不是Java和Python的连接器

关键类

  • PythonInterpreter
    • exec 执行语句
    • set 设置变量值
    • get 获取变量值
    • execfile执行一个python文件
  • PyObject
  • PyFunction
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 执行Python程序语句
PythonInterpreter pi = new PythonInterpreter();
pi.exec("import sys");
pi.set("a", new PyInteger(42));
pi.exec("print a");
pi.exec("x = 2+2");
PyObject x = pi.get("x");
System.out.println("x: " + x);

//执行Python文件
PythonInterpreter pi = new PythonInterpreter();
pi.execfile("src/main/java/edu/ecnu/hello.py");
pi.cleanup();
pi.close();

//执行Python文件并传参
try (PythonInterpreter pi = new PythonInterpreter()) {
pi.set("cnt", 5);
pi.execfile("src/main/java/edu/ecnu/randomSum.py");
PyObject sum = pi.get("sum");
System.out.println("Sum is: " + sum);
}
/*
src/main/java/edu/ecnu/randomSum.py
from java.util import Random
r = Random()
sum = 0
for i in xrange(cnt):
randomNum = r.nextInt()
print randomNum
sum += randomNum
*/

//调用Python程序中的函数
PythonInterpreter pi = new PythonInterpreter();
pi.execfile("src/main/java/edu/ecnu/calculator1.py");
PyFunction pf = pi.get("power", PyFunction.class);
PyObject result = pf.__call__(Py.newInteger(2), Py.newInteger(3)); //2^3
System.out.println(result);
pi.cleanup();
pi.close();
/*
src/main/java/edu/ecnu/calculator1.py
import math

def power(x, y):
return math.pow(x, y)
*/

//调用Python程序中的类
PythonInterpreter pi = new PythonInterpreter();
pi.execfile("src/main/java/edu/ecnu/calculator2.py");

//在Java中调用Python对象实例的方法
String pythonClassName = "Calculator"; // python类名
String pythonObjName = "cal"; // python对象名
pi.exec(pythonObjName + "=" + pythonClassName + "()"); // 实例化python对象
PyObject pyObj = pi.get(pythonObjName); // 获取实例化的python对象

// 调用python对象方法,传递参数并接收返回值
PyObject result = pyObj.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)});
double power = Py.py2double(result);
System.out.println(power);
pi.cleanup();
pi.close();
/*
import math

class Calculator(object):

def power(self, x, y):
return math.pow(x,y)
*/

5.Web Service

  • 由万维网联盟(W3C, World Wide Web Consortium)提出
  • 消除语言差异、平台差异、协议差异和数据结构差异,成为不同构件模型和异构系统之间的集成技术
  • Web Service是为实现跨网络操作而设计的软件系统,提供了相关的操作接口,其他应用可以使用SOAP消息,以预先指定的方式来与Web Service进行交互

wsimport 工具

  • %JAVA_HOME%\bin目录下
  • 根据wsdl文档,自动产生客户端中间代码
1
wsimport -keep -verbose http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL

基本步骤

  • 调用wsimport所产生客户端中间代码
  • 提供相应参数
  • 获取返回结果
1
2
3
4
5
6
7
8
9
10
11
12
/**
* use wsimport to parse wsdl
* wsimport -keep -verbose http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
* copy the generated class to this project, and invoke them
*
* 调用手机号查询web service
* @param args
*/
MobileCodeWS mobileCodeWS = new MobileCodeWS();
MobileCodeWSSoap mobileCodeWSSoap = mobileCodeWS.getMobileCodeWSSoap();
String tel=mobileCodeWSSoap.getMobileCodeInfo("13722222222",null); //修改为有效号码
System.out.println(tel);
  • Java 调用 Web Service 其他办法
    • Axis/Axis2 (axis.apache.org)
    • 采用URLConnection访问 Web Service
    • 采用HttpClient访问Web Service

6.命令行

Runtime

  • Java提供Runtime类
    • exec 以一个独立进程执行命令command, 并返回Process句柄
    • 当独立进程启动后,需要处理该进程的输出流/错误流
      • 调用Process.getInputStream 可以获取进程的输出流
      • 调用Process.getErrorStream可以获取进程的错误输出流
    • 调用Process.waitFor 等待目标进程的终止(当前进程阻塞)
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
Process p;
String cmd = "ipconfig /all"; //查看ip地址

try {
// 执行命令
p = Runtime.getRuntime().exec(cmd);
// 取得命令结果的输出流
InputStream fis = p.getInputStream();
// 用一个读输出流类去读
InputStreamReader isr = new InputStreamReader(fis);
// 用缓冲器读行
BufferedReader br = new BufferedReader(isr);
String line = null;
// 直到读完为止
while ((line = br.readLine()) != null) {
System.out.println(line);
}

System.out.println("");
int exitVal = p.waitFor(); //获取进程最后返回状态
System.out.println("Process exitValue: " + exitVal);

} catch (Exception e) {
e.printStackTrace();
}