0
1

java勉強:J2V8とJavetの比較

Last updated at Posted at 2023-10-13

V8はGoogleが開発するオープンソースのJavaScriptエンジンです。高速、最新ES適用など、いろいろほめられています。V8はC++のものですが、javaからV8から利用する場合、ラッパーが必要です。

  • 一番有名なのは、J2V8です。だが更新が止まっているみたいで、windows向けのバージョンは2016年の4.6.0まで、async/awaitはサポートしていないです。詳細は以下のリンクから確認してください。

  • 2番めは、javetです。V8の2023年10月のv11.8.172.15、node.jsも9月v20.8.0を利用されています。認知度がJ2V8よりちょっと低いかもしれません。後発ですからJ2V8より使い勝手がいいです。

<dependency>
    <groupId>com.caoccao.javet</groupId>
    <artifactId>javet</artifactId>
    <version>3.0.0</version>
</dependency>

J2V8とJavetの使い勝手の違い

testa.js

global.myVar="aaaaaaaaaa";

testb.js

global.myVar="bbbbbbbbbb";

testJ2V8.java

import java.io.File;
import java.io.IOException;

import com.caoccao.javet.exceptions.JavetException;
import com.eclipsesource.v8.NodeJS;

public class TestJ2V8 {
	public static void main(String[] args) throws IOException,  InterruptedException, JavetException {
		final NodeJS nodeJS = NodeJS.createNodeJS();
		File testa=new File("testa.js");
		nodeJS.exec(testa);
		File testb=new File("testb.js");
		nodeJS.exec(testb);
		while (nodeJS.isRunning()) {//実行完了まで待つ
			nodeJS.handleMessage();
		}
		System.out.println(nodeJS.getRuntime().getString("myVar"));
		nodeJS.release();
	}
}

TestJavet.java

import java.io.File;
import java.io.IOException;

import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.executors.IV8Executor;

public class TestJavet {
	public static void main(String[] args) throws IOException,  InterruptedException, JavetException {
		try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {
			IV8Executor iV8Executor=v8Runtime.getExecutor(new File("testa.js"));
			iV8Executor.executeVoid();
			v8Runtime.await();//実行完了まで待つ
			iV8Executor=v8Runtime.getExecutor(new File("testb.js"));
			iV8Executor.executeVoid();
			v8Runtime.await();//実行完了まで待つ
			System.out.println(v8Runtime.getGlobalObject().getString("myVar"));
		}
	}
}

javetのv8Runtime.await()呼び出しは、j2v8のwhile (nodeJS.isRunning()) と類似役割の目的ですが、v8Runtime.await()は何回呼び出しても構わないです。while (nodeJS.isRunning())は1回しか呼び出せなくて、実行後V8は停止状態になってこれ以上jsファイルを実行できません。j2v8には、v8Runtime.await()に相当するものがありません。だって2016年のものですから。

そして、j2v8は、efwのloadWithGlobalPool関数の内蔵javaScriptエンジンとして利用することは不可能です。プールから取得して利用して返すことは、エンジンの利用は1回限りではなく、断続で何回にもなるからです。

また、javetは、Primitive ConverterとObject Converterの仕組みがあって、javaとjavascript間の変換が自動的に行ってくれます。j2v8にはPrimitive Converterの類似仕組みがありますが、Object Converterと同等するものがありません。そして、Byte[]をjavaからエンジンに渡す場合、手動でV8Arrayに変換してエンジンに渡しています。その分の勉強と手間が発生しなければなりません。

J2V8とJavetのマルチスレッドの違い

結論からいうと、J2V8はマルチスレッド禁止です。JavetはマルチスレッドがOKです。

  • まずJ2V8とJavetのラインタイムをstatic変数に定義します。
package test;
import com.eclipsesource.v8.V8;
public class TestJ2V82 {
	public static V8 runtime = V8.createV8Runtime();
	static {
		runtime = V8.createV8Runtime();
		runtime.executeVoidScript("var c=0;function hello(){c++;return c;};");
	}
}
package test;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
public class TestJavet2 {
	public static V8Runtime v8Runtime;
	static {
		try {
			v8Runtime = V8Host.getNodeInstance().createV8Runtime();
			v8Runtime.getExecutor("var c=0;function hello(){c++;return c;};").executeVoid();
		} catch (JavetException e) {
			e.printStackTrace();
		}
	}
}

それぞれのstatic変数を利用するjspを作成します。
test_subJ2V8.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="test.TestJ2V82"%>
<%@ page import="com.eclipsesource.v8.V8"%>

<%
	V8 runtime =TestJ2V82.runtime;
	out.println(runtime.executeStringScript("''+hello();"));
	out.println("<br>");
	out.println(runtime.executeStringScript("''+hello();"));
%>

test_subJavet.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="test.TestJavet2"%>
<%@ page import="java.io.File"%>
<%@ page import="java.io.IOException"%>
<%@ page import="com.caoccao.javet.exceptions.JavetException"%>
<%@ page import="com.caoccao.javet.interop.V8Host"%>
<%@ page import="com.caoccao.javet.interop.V8Runtime"%>
<%@ page import="com.caoccao.javet.interop.executors.IV8Executor"%>

<%
	V8Runtime v8Runtime=TestJavet2.v8Runtime;
	out.println(v8Runtime.getExecutor("hello()").executeInteger());
	out.println("<br>");
	out.println(v8Runtime.getExecutor("hello()").executeInteger());
%>

上記jspを同時10回を呼び出すテスト画面を作ります。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="efw" uri="efw" %> 
<!DOCTYPE HTML>
<HTML>
<HEAD>
	<META HTTP-EQUIV="CONTENT-TYPE"CONTENT="TEXT/HTML;CHARSET=UTF-8">       
	<TITLE>efw Output Test</TITLE>
	<!-- Efwクライアントの取り込み-->
	<efw:Client lang="jp"/>
	<script>
	function testJavetM(flg){
		$("#pdf0")[0].src="";
		$("#pdf1")[0].src="";
		$("#pdf2")[0].src="";
		$("#pdf3")[0].src="";
		$("#pdf4")[0].src="";
		$("#pdf5")[0].src="";
		$("#pdf6")[0].src="";
		$("#pdf7")[0].src="";
		$("#pdf8")[0].src="";
		$("#pdf9")[0].src="";
		setTimeout(function(){
			$("#pdf0")[0].src="test_sub"+flg+".jsp";
			$("#pdf1")[0].src="test_sub"+flg+".jsp";
			$("#pdf2")[0].src="test_sub"+flg+".jsp";
			$("#pdf3")[0].src="test_sub"+flg+".jsp";
			$("#pdf4")[0].src="test_sub"+flg+".jsp";
			$("#pdf5")[0].src="test_sub"+flg+".jsp";
			$("#pdf6")[0].src="test_sub"+flg+".jsp";
			$("#pdf7")[0].src="test_sub"+flg+".jsp";
			$("#pdf8")[0].src="test_sub"+flg+".jsp";
			$("#pdf9")[0].src="test_sub"+flg+".jsp";
		},100);
	}
	</script>
</HEAD>
<BODY>
<button onclick="testJavetM('Javet');">マルチJavet</button>
<button onclick="testJavetM('J2V8');">マルチJ2V8</button>
<br>
<iframe id="pdf0" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf1" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf2" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf3" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf4" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf5" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf6" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf7" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf8" src="" style="width:400px;height:300px"></iframe>
<iframe id="pdf9" src="" style="width:400px;height:300px"></iframe>
</BODY>
</HTML>

実行の結果はこれです。
J2V8は、1回目成功、その後は全部失敗です。失敗の理由は、org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.Error: Invalid V8 thread access です。
image.png

Javetは全部成功です。
image.png

  • マルチスレッドについて、Graaljsもだめです。QuickJSもだめです。逆にむかしのNashornとRhinoは可能です。ようやくES2015以上サポート且つマルチ可能のエンジンを見つかりました。

結論

Javetはいいね。これから利用してみましょう。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1