上篇文章简单提了下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

node-java的使用及源码分析的更多相关文章

  1. 死磕 java集合之ConcurrentHashMap源码分析(三)

    本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...

  2. 死磕 java集合之LinkedList源码分析

    问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...

  3. Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析

    Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...

  4. 【死磕 Java 集合】— ConcurrentSkipListMap源码分析

    转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...

  5. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

  6. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  7. 死磕 java集合之PriorityBlockingQueue源码分析

    问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...

  8. 死磕 java集合之PriorityQueue源码分析

    问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...

  9. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计

    问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...

  10. 死磕 java集合之LinkedHashSet源码分析

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

随机推荐

  1. Go 常用函数

    #### Go 常用函数,错误处理这一节我们来学习一下Go 常用的函数,这些函数有些是内置的,有些是官方标准库内的, 熟悉这些函数对程序开发来讲还是很重要的; 1. len("abc&quo ...

  2. Windows如何搭建SSL通信(非Web)

    自己研究了会儿,把结论发出来给有需要的人 第一步:准备环境 首先需要一台服务器(这不是废话吗),我这边用的windows2003, 还需要一台客户端,我用的是windwos2008 第二步:服务器环境 ...

  3. MySQL运维开发之路

    MySql h1 { color: rgba(0, 60, 128, 1); text-align: center } h1:hover { color: rgba(0, 255, 111, 1) } ...

  4. ApacheCN 计算机视觉译文集 20210203 更新

    新增了五个教程: OpenCV3 和 Qt5 计算机视觉 零.前言 一.OpenCV 和 Qt 简介 二.创建我们的第一个 Qt 和 OpenCV 项目 三.创建一个全面的 Qt + OpenCV 项 ...

  5. 「JOISC 2014 Day4」两个人的星座

    首先突破口肯定在三角形不交,考虑寻找一些性质. 引理一:两个三角形不交当且仅当存在一个三角形的一条边所在直线将两个三角形分为异侧 证明可以参考:三角形相离充要条件,大致思路是取两个三角形重心连线,将其 ...

  6. 洛谷 P4708 画画(无标号欧拉子图计数)

    首先还是类似于无标号无向图计数那样,考虑点的置换带动边的置换,一定构成单射,根据 Burnside 引理: \[|X / G| = \frac{1}{|G|}\sum\limits_{g \in G} ...

  7. 关于IBAction、IBOutlet前缀IB的解释

    - 全称:Interface Builder - 以前的UI界面开发模式:Xcode3 + Interface Builder - 从Xcode4开始,Interface Builder已经整合到Xc ...

  8. 云端iclound使用-陈棚

    使用NSmetadataQuery查询文档,增加,删除,编辑 界面设计完成后效果如图: 程序清单:FKDiary.h @interface FKDiary : UIDocument @property ...

  9. postman常用测试脚本

    测试脚本: 设置环境变量 var jsonData = JSON.parse(responseBody); postman.setGlobalVariable("5KMST", j ...

  10. nodejs串行无关联

    var async = require('async'); //串行无关联async.series({ one:function(cb) { setTimeout(function(){ consol ...