MOOC 个人学习笔记
# 1.RMI
- RMI:Remote Method Invocation 远程方法调用
- 两个位于不同 JVM 虚拟机的 Java 程序互相请求访问
# RMI 的参数和返回值
- (自动化) 传递远程对象 (实现 Remote 接口)
- 当一个对远程对象的引用从一个 JVM 传递到另一个 JVM,该远程对象的发送者和接收者将持有同一个实体对象的引用。这个引用并非是一个内存位置,而是由网络地址和该远程对象的唯一标识符构成的。
### 两个 JVM 拥有同一个对象 ###
- 当一个对远程对象的引用从一个 JVM 传递到另一个 JVM,该远程对象的发送者和接收者将持有同一个实体对象的引用。这个引用并非是一个内存位置,而是由网络地址和该远程对象的唯一标识符构成的。
- (自动化) 传递可序列化对象 (实现 Serializable 接口)
- JVM 中的一个对象经过序列化后的字节,通过网络,其副本传递到另一个 JVM 中,并重新还原为一个 Java 对象。
### 每个 JVM 拥有自己的对象 ###
- JVM 中的一个对象经过序列化后的字节,通过网络,其副本传递到另一个 JVM 中,并重新还原为一个 Java 对象。
//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 函数
class HelloNative { | |
public static native void greeting(); | |
} |
- 调用 javac.exe 编译,得到 HelloNative.class
- 调用 javah.exe 得到包含该方法 (Java_HelloNative_greeting) 的头文件 HelloNative.h
- 实现.c 文件 (对应 HelloNative.h)
#include "HelloNative.h" | |
JNIEXPORT void JNICALL Java_HelloNative_greeting(JNIEnv* env, jclass cl) { | |
printf("Hello Native World\n"); | |
} |
- 将.c 和.h 文件,整合为共享库 (DLL) 文件
- 在 Java 类中,加载相应的共享库文件
HelloNative.greeting(); | |
static { | |
System.loadLibrary("HelloNative"); //dll 名字 | |
} |
# 3.Nashorn
- 脚本引擎,ScriptEngine
- Nashorn,JDK 8 自带的 JS 解释器 (JDK6/7 是 Rhino 解释器)
ScriptEngine engine = new ScriptEngineManager().getEngineByName(“nashorn”) |
- 主要方法
- eval,执行一段 js 脚本. eval (String str), eval (Reader reader)
- put,设置一个变量
- get,获取一个变量
- createBindings, 创建一个 Bindings
- setBindings, 设置脚本变量使用的范围
//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 类型 | 文件扩展 |
---|---|---|---|
Nashorn | nashorn,js | text/javascript | js |
Groovy | groovy | 无 | groovy |
Renjin | Renjin | text/x-R | R,r,S,s |
SISC Scheme | sisc | 无 | scheme,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
// 执行 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 文档,自动产生客户端中间代码
wsimport -keep -verbose http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL
# 基本步骤
- 调用 wsimport 所产生客户端中间代码
- 提供相应参数
- 获取返回结果
/** | |
* 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 等待目标进程的终止 (当前进程阻塞)
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(); | |
} |