上篇文章简单提了下node调用java的方法但也只属于基本提了下怎么输出helloworld的层度,这次将提供一些案例和源码分析让我们更好地了解如何使用node-java库。

前置知识:

1.桥接模式 http://c.biancheng.net/view/1364.html
2.nodejs和c++交互 http://nodejs.cn/api/addons.html
3.java和c++交互 https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
4.大概了解classloader机制

node-java原理:

通过c++桥接 [js <-> c++(v8、jvm) <-> java(jar)] 的方式调用jar

案例地址:

https://gitee.com/lablelan/nodejs_demo.git
源码在nodeJava目录

案例演示:

demo0
通过创建子进程方式调用jar
demo1
调用jar输出hello world
demo2
node进程编码为base64由jvm解码返回结果
demo3
调用jar里的测试接口导出数据
demo4
模拟jar里的测试接口导出数据
demo5
使用jar包导出100万行数据到本地
demo6
使用express和excel-export包导出数据
demo7
使用easyexcel的jar包导出数据
demo8
使用promise方式导出数据
demo9
调用sm4(国密)的jar加解密 https://www.javajike.com/book/hutool/chapter8/eb920b20c199717f34f28a89fcf6d620.html
demo10
将业务跑在worker线程上

用到的jar包源码:

easyexcel: https://github.com/alibaba/easyexcel
utils: ./java/Util
myutils: ./java/myutils

node-java源码:

https://github.com/joeferner/node-java

核心源码目录:

.
├── index.js
├── lib
│ └── nodeJavaBridge.js # index.js入口这里开始初始化java对象
└── src
├── java.cpp
├── java.h # java类 初始化jvm、提供一些基础类型实例化接口和调用代理
├── javaObject.cpp
├── javaObject.h # java对象代理 我们的Sync后缀等方法就是从这里被加进对象的原型中
├── javaScope.cpp
├── javaScope.h # 管理局部引用生命周期
├── methodCallBaton.cpp
├── methodCallBaton.h # 管理v8和jvm对象内存,提升全局作用域等
├── nodeJavaBridge.cpp # 桥接暴露给v8
├── node_NodeDynamicProxyClass.h # 动态代理类 提供多线程功能
├── utils.cpp
└── utils.h # v8和jvm对象转换工具

带着问题去看源码:

1.如何查看一个对象的Java类型?

// Nan::SetPrototypeTemplate(funcTemplate, methodNameSync, methodCallSyncTemplate);
const ArrayList = java.import('java.util.ArrayList');
const arrayList = new ArrayList();
// 调用java的getClass方法可以获得类名称,这里的类名称被加工过,但可以大概看得出类路径
console.log(ArrayList, arrayList, arrayList.getClassSync())

2.如何知道对象/类有什么方法?

// 从源码上看可以得出java的方法会注入到原型中并带上后缀
const ArrayList = java.import('java.util.ArrayList');
const arrayList = new ArrayList();
console.log(arrayList.__proto__)

3.他是如何加载jar包的?

// 可以看出最终classpath会通过jni接口创建虚拟机时当做参数传入
Nan::SetAccessor(this->handle(), Nan::New<v8::String>("classpath").ToLocalChecked(), AccessorProhibitsOverwritingGetter, AccessorProhibitsOverwritingSetter);
classPath << *arrayItemStr;
vmOptions[0].optionString = strdup(classPath.str().c_str());
args.options = vmOptions;
JNI_CreateJavaVM(&jvmTemp, (void **)env, &args);

4.对象的生命周期是什么样的?

When you call a Java method through node-java, any arguments (V8/JavaScript objects) will be converted to Java objects on the v8 main thread via a call to v8ToJava (found in utils.cpp). The JavaScript object is not held on to and can be garbage collected by v8. If this is an async call, the reference count on the Java objects will be incremented. The Java method will be invoked in a node.js async thread (see uv_queue_work). When the method returns, the resulting object will be returned to the main v8 thread and converted to JavaScript objects via a call to javaToV8 and the Java object's reference count will then be decremented to allow for garbage collection. The resulting v8 object will then be returned to the callers callback function.

5.java和js对象如何转换?

// utils.cpp上有两个函数进行对象转换
jobjectArray v8ToJava(JNIEnv* env, Nan::NAN_METHOD_ARGS_TYPE args, int start, int end);
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg);

6.为什么对象的方法会自动带上Sync?

// 在javaObject.cpp可以看到javaToV8时会将java类上的方法放到v8对象上,带Sync为运行在v8主线程上,不带Sync则放进workerQueue等待其他线程处理(需要回调)
const char* methodNameSync = methodNameSyncStr.append(java->SyncSuffix()).c_str();

ps:

1.项目可以使用 node-gyp rebuild 对c++代码进行重新编译,如需重新编译可以执行 npm rebuild
2.遇到 java_dll_path.json 找不到的情况可以在 /node_modules/java 执行 node postInstall.js

最新文章

  1. TP-link TL-WN725 USB无线网卡在DX2 CPU下的Xlinux 驱动移植
  2. jQuery .css color 重写 :hover样式没了
  3. 【PHP&amp;&amp;FileIO】
  4. TRUNCATE,DORP,DELETE
  5. poj 1163 The Triangle
  6. linux 入门
  7. 阿里云linux服务器安装Phalcon-----&quot;phalcon Volt directory can&#39;t be written&quot; &quot;gcc: internal compiler error: Killed (program cc1)&quot;
  8. MvcPager
  9. 拓扑序+dp Codeforces Round #374 (Div. 2) C
  10. (三目运算符)PHP中问号?和冒号: 的作用
  11. spring mvc和web-flow的整合方案
  12. mysql 水平分表
  13. Peer Programming Project: 4 Elevators Scheduler 附加题 157 165
  14. SpringBoot 使用Druid连接池
  15. WebService简单教程
  16. cogs1538 [AHOI2005]LANE 航线规划
  17. net 反编译神器
  18. EasyFastCMS系列教学课程——1、三层框架的搭建
  19. Webdriver--获得验证信息
  20. 怎样实现动态加入布局文件(避免 The specified child already has a parent的问题)

热门文章

  1. Linux下安装confluence汉化破解版
  2. ant -design vue a-tree 树形控件
  3. 【webpack4.0】---dev.config.js基本配置(六)
  4. STL中的隐性性能开销与副作用
  5. 反汇编分析C++代码
  6. JAVA多线程学习八-多个线程之间共享数据的方式
  7. VC 获取当前运行窗口名称
  8. IDEA中Git的一般使用场景
  9. 分布式消息队列RocketMQ(一)安装与启动
  10. JS 获取JSON返回的时间值转换为通常格式展示