上篇文章简单提了下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. Unity——日志打印工具

    一.日志工具功能 封装Debug类,需要实现功能: 1.控制所有日志是否打印: 2.除了Log,Warning,Error外,给更多日志种类(不同颜色): 3.格式化打印日志: 4.不定参数,自动拼接 ...

  2. Java 线程学习笔记

    1.什么是线程 进程: 一个正在运行的程序就叫一个进程. 每个进程都有独立的内存空间. (进程是资源分派的基本单位) 线程: 一个进程中可以有很多线程.----> 常说的多线程 线程没有独立的内 ...

  3. Vue之watch监听对象中某个属性的方法

    新建 userinfo = { name: "小明",  age: "18", } vue中watch监听name的方法 1. 可以结合计算属性的方法实现 { ...

  4. plsql 视图中 为什么使用替代触发器

    /* 什么是视图? 视图:数据库对象,存的是一个查询命令:当作一个虚拟的数据表来使用: 应用场景: 简化查询操作:不能直接在视图上进行create,insert,update操作: 创建视图? 需要管 ...

  5. Redis学习笔记(二)redis 底层数据结构

    在上一节提到的图中,我们知道,可以通过 redisObject 对象的 type 和 encoding 属性.可以决定Redis 主要的底层数据结构:SDS.QuickList.ZipList.Has ...

  6. .net core部署到ubuntu 上传文件超过30MB

    默认的上传文件不能超过30MB,需要修改几个地方 一.web.config中添加配置 <requestLimits maxAllowedContentLength="214748364 ...

  7. 常见消息处理api

    面试:子线程一定不能更新UI? SurfaceView :多媒体视频播放 ,可以在子线程中更新UI: Progress(进度)相关的控件:也是可以在子线程中更新Ui;审计机制:activity完全显示 ...

  8. 实现“手机qq”侧滑菜单 -- 吴欧

    基本数据采集 经过体验,手机QQ采用的应该是线性动画,即视图缩放比例等随手指在屏幕上滑动的距离以一次方程的形式变化. 提取基本数据,向右侧滑达到最大幅度时: 1.   右侧主视图左边界距离屏幕左边界的 ...

  9. 一招教你IDEA中Java程序如何打包,以及打包后如何运行

    前言 编写程序 程序打包 测试运行 IDEA作为目前按最主流的Java程序项目编写工具,越来越受到开发人员的青睐.idea因为其五花八门的功能,让你在开发过程中效率显著提高.那么对于初学者来说,如何通 ...

  10. day2 -- 字符串常用方法、列表、字典

    1.字符串常用方法 name = "Convict abc" count(): print(name.count("c")) # 2 find(): print ...