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 ... 
随机推荐
- 项目管理软件jira安装
			JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪.客户服务.需求收集.流程审批.任务跟踪.项目跟踪和敏捷管理等工作领域. 官方文档https://confluence.a ... 
- MySQL数据类型操作(char与varchar)
			目录 一:MySQL数据类型之整型 1.整型 2.验证不同类型的int是否会空出一个存储正负号 3.增加约束条件 去除正负号(unsigned) 二:浮点型 1.浮点型 2.验证浮点型精确度 三:字符 ... 
- 近期Android学习II
			一晃眼又过了5天,这几天的学习有些杂乱,半年在家没运动,返校了准备慢慢恢复运动,身体才是革命的本钱~ 四天跑了三回步,每次都死亡喘息= = 这几天的学习重点总归还是放在Android上了,前面31天连 ... 
- react之withRouter的作用
			withRouter的作用:把不是通过路由切换过来的组件,将react-router的history.location和match三个对象传入到props对象上: 默认情况下必须是经过路由匹配渲染的组 ... 
- Disruptor-高性能队列
			简介 Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题.与Kafka.RabbitMQ用于服务间的消息队列不同,disruptor一般用于线程间消息 ... 
- python基础篇-爬虫urlparse使用及简单示例
			>>> from urllib.parse import urlparse >>> o = urlparse('http://www.cwi.nl:80/%7Egu ... 
- Ubuntu16.04的PHP开发环境配置
			\3c a { text-decoration: none } 自从换了php开发之后发现还是开源语言才是长久之道,开发环境搭建方便,支持的平台也多,性能也好,考虑到这些,其他一些不如意也就不足为虑了 ... 
- java中静态代码块详解
			感谢大佬:https://blog.csdn.net/qq_35868412/article/details/89360250 今天在项目中看到这行代码,静态代码块,很久没用静态代码块了,今天来复习一 ... 
- aidl的应用场景
			支付宝 package com.tesy.alipay; import com.test.alipay.Iservice.Stub; import android.app.Service; impor ... 
- go基础——goto语法
			package main import "fmt" func main() { a := 10 LOOP: for a < 20 { if a == 15 { a += 1 ... 
