node-java的使用及源码分析
上篇文章简单提了下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的使用及源码分析的更多相关文章
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- 死磕 java集合之LinkedList源码分析
问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...
- Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析
Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...
- 【死磕 Java 集合】— ConcurrentSkipListMap源码分析
转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...
- java线程池ThreadPoolExector源码分析
java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...
- 死磕 java集合之DelayQueue源码分析
问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...
- 死磕 java集合之PriorityBlockingQueue源码分析
问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...
- 死磕 java集合之PriorityQueue源码分析
问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...
- 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...
- 死磕 java集合之LinkedHashSet源码分析
问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...
随机推荐
- ping: Network is unreachable
问题 [root@web-1 yum.repos.d]# ping baidu.com ping: unknown host baidu.com [root@web-1 yum.repos.d]# p ...
- React之常用技术栈
· react-redux:https://www.cnblogs.com/jingxuan-li/p/12439181.html · react-router-dom:https://www.c ...
- 社交网络分析的 R 基础:(四)循环与并行
前三章中列出的大多数示例代码都很短,并没有涉及到复杂的操作.从本章开始将会把前面介绍的数据结构组合起来,构成真正的程序.大部分程序是由条件语句和循环语句控制,R 语言中的条件语句(if-else)和 ...
- [USACO18DEC]The Cow Gathering P
首先可以思考一下每次能删去的点有什么性质. 不难发现,每次能删去的点都是入度恰好为 \(1\) 的那些点(包括 \(a_i \rightarrow b_i\) 的有向边). 换句话说,每次能删去的点既 ...
- 双系统之删除Linux以及grub的引导
问题阐述:最近玩双系统,把linux系统搞崩了,回到windos备份Linux系统的数据就把Linux的盘格式化了,然后再每当进入系统都会出现grub的命令格的窗口,输入任何命令都报错? 解决方法: ...
- 设置程序启动时加载的storyboard
这个设置表明:程序启动时会加载Main.storyboard
- KVC替换系统的tabbar为自定义tabbar---秀清
CustomTabbar *tabbar = [[CustomTabbar alloc]init]; //KVC,更换系统的tabbar为自定义tabbar tabbar.tabbarDelegate ...
- jdk1.5新特性之------->可变参数
/* jdk1.5新特性之------->可变参数 需求: 定义一个函数做加法功能(函数做几个数据 的加法功能是不确定). 可变参数的格式: 数据类型... 变量名 可变参数要 注意的细节: 1 ...
- .NET 6全文检索引擎Lucene.NET 4.8简单封装
前言 因为最近在做一个检索数据的工具.最开始用的Mysql8自带的全文检索功能.但是发现这货数据量超过百万之后,检索速度直线下降. 于是想到Lucene.net.花了一晚上时间做了简单的封装.可以直接 ...
- http的报文结构和状态码总结
1.HTTP报文结构 请求报文 报文由三个部分组成,即开始行.首部行和实体主体.在请求报文中,开始行就是请求行. 响应报文 响应报文的开始行是状态行.状态行包括三项内容,即HTTP的版本,状态码,以及 ...