Java/Spring과 Node.js의 공존 시즌2
(부제: Java/Spring 전성시대에 Node.js가 살아남는 법)
J2V8을 활용한 자바에 빌붙기
Dongsu Jang <iolothebard at gmail dot com>
발표자료
http://slideshare.net/iolo
제주사는/마이너지향/입코딩전문/독거중년/개발자
이 분
이
바로...
만렙 음유시
그러
나,
현실은...
독거중년
아무도 궁금해 하지 않는…
iolo-the-bard
TOC
• BEGIN
• AS-IS
• Nashorn
• ScriptTemplateView
• Node.js
• TO-BE
• J2V8
• VS
• CODE
• END
BEGIN
JUST FOR FUN
개발자여,
불가능한 꿈을 꾸어라
• Just For Fun
• Open Source
• MSA
• Polyglot
• IE8 없는 세상…
그러나,
리얼리스트가 되라
• 현실은 자바 천국…
• 스프링 전성 시대…
• 봄날은 생각보다 오래 가더라…
• Write Once, Ops Forever!
• IE8만 없어지면 될 줄 알았지?
그래도…
npm에 좋은거 많다던데…
J2V8의 역습
J2V8 STRIKES BACK
Java/Spring과 Node.js의 공존 시즌2
AS-IS
AS GOOD AS IT GETS
Spring Velocity DEPRECATED
에 대처하는 우리의 자세
• Thymeleaf?
• 다시 JSP?
• 그냥 Velocity?!
• 참고: https://jira.spring.io/
browse/SPR-13235
React Isomorphic Rendering
에 대처하는 우리의 자세
• React?
• Isomorphic?
• 먹는거임?
• 대세 or Hype!
빌붙기의 기술
• Rhino
• Nashorn
• Node.js
• J2V8
Rhino
• built-in since Java6
• Oldies but Goodies
• Slooooow but Elegant
• 참고: https://
developer.mozilla.org/en-
US/docs/Mozilla/Projects/
Rhino
Nashorn
• built-in since Java8
• Fast & Easy
• try `jrunscript`
• JSR-223 Scripting API
• 참고: http://
openjdk.java.net/projects/
nashorn/
Hello World
with Nashorn
function greeting(name) {
return "hello," + name + "!";
}
ScriptEngine engine = new
ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("hello.js"));
Invocable invocable = (Invocable)engine;
Object result = invocable.invokeFunction(
"greeting", "World");
System.out.println(result);
React Isomorphic Rendering
with Nashorn
tomcatapache
webapp
(war)
MySQL
Nashorn
mod_jk
AJPHTTP
JVM
glue
script
ReactDOMServer.renderToString()
자바 기반 템플릿 엔진
React Isomorphic Rendering
with Nashorn
function renderToString(type, props) {
return ReactDOMServer.renderToString(type, props);
}
<div id="main">${reactHtml}</div>
<script src="bundle.js"></script>
$.getJSON('/apis/v1/comments', function (data) {

ReactDOM.render(<CommentList comments={ data }/>,
document.getElementById('main'));

});
React Isomorphic Rendering
with Nashorn
@RequestMapping("/comment_list")
String getCommentList(Model model) {
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("nashorn");
engine.eval(new FileReader("polyfill.js"));
engine.eval(new FileReader("react.js"));
engine.eval(new FileReader("react-dom-server.js"));
engine.eval(new FileReader("render.js"));
Invocable invocable = (Invocable)engine;
String reactHtml = (String)invocable.invokeFunction(
"renderToString", "CommentList",
demoService.getComments());
model.addAttribute("reactHtml", reactHtml);
return "comment_list";
}
ScriptTemplateView
• since Spring 4.2
• Easy!!
• JSR-223 Scripting API
• Nashorn, Rhino, JRuby,
Jython, …
• Template Engines
• Hadlebars, Mustache, ejs,
Jade and erb, Jinja2, …
ScriptTemplateView
tomcatapache
webapp
(war)
MySQL
Script
Template
View
mod_jk
AJPHTTP
JVM
glue
script
render(template, model, url)
스크립트 언어 기반 템플릿 엔진
ScriptTemplateView
with ejs/Nashorn
@RequestMapping(“/comment_list”)

public String server(Model model) {

model.addAttribute(“comments”,
demoService.getComments());

return "comment_list";

}
<ul>

<% comments.forEach(function (comment) { %>

<li>

<h5><%= comment.content %></h5>

<p><%= comment.author %></p>

</li>

<% }); %>

</ul>
ScriptTemplateView
with ejs/Nashorn
var _compiledTemplates = {};

function render(template, model, url) {

var compiledTemplate = templates[url];

if(!_compiledTemplates[url]) {

_compiledTemplates[url] = compiledTemplate
= ejs.compile(template);

}

return compiledTemplate(toJsonObject(model));

}

function toJsonObject(javaObj) {

var jsonObj = {};

for (var k in javaObj) {

if(javaObj[k] instanceof Java.type("java.lang.Iterable")) {

jsonObj[k] = Java.from(javaObj[k]);

} else {

jsonObj[k] = javaObj[k];

}

}

return jsonObj;

}
ScriptTemplateView
with ejs/Nashorn
@Configuration

public class EjsConfig {

@Bean

public ScriptTemplateConfigurer scriptTemplateConfigurer() {

ScriptTemplateConfigurer bean = new ScriptTemplateConfigurer();

bean.setEngineName("nashorn");

bean.setScripts(

"/server-scripts/nashorn-polyfill.js",

"/META-INF/resources/webjars/ejs/2.4.1/ejs-v2.4.1/ejs.min.js",

"/server-scripts/nashorn-ejs-render.js"

);

bean.setRenderFunction("render");

bean.setSharedEngine(true);

return bean;

}

@Bean

public ViewResolver scriptTemplateViewResolver() {

ScriptTemplateViewResolver bean = new ScriptTemplateViewResolver();

bean.setPrefix("classpath:/templates/ejs/");

bean.setSuffix(".ejs");

return bean;

}

}
Node.js
• Polyglot, MSA or Hype?
• Fast & Easy
• but Another World
• npm에 좋은거 많다던데…
• 참고: https://nodejs.org
React Isomorphic Rendering
with Node.js
tomcatapache
webapp
(war)
MySQL
express
mod_jk
AJPHTTP
JVM
app.js
ReactDOMServer.renderToString()
자바 기반 템플릿 엔진
HTTP
Node.js
HTTP
React Isomorphic Rendering
with Node.js
var ReactDOMServer = require(‘react-dom/server’);
var CommentList = require(‘comment_list’);
app.get(‘/comment_list’, function (req, res, next) {
db.getCommentList(function (err, data) {
ReactDOMServer.renderToString(<CommentList comments={data}/>);
res.send(reactHtml);
};
});
@RequestMapping("/comment_list")
String getCommentList(Model model) {
String reactHtml = restTemplate.getForObject(
"http://localhost:3000/comment_list", String.class);
model.addAttribute("reactHtml", reactHtml);
return "comment_list";
}
<div id="main">${reactHtml}</div>
<script src="bundle.js"></script>
TO-BE
STAY HUNGRY STAY FOOLISH
J2V8
• Open Source Java bindings
for V8
• Licensed under the EPL
• Faaaaast Fresh!
• Run on Java6
• not only V8 but also NodeJS
• Linux, Windows, Mac OS X,
Android ARM, Android x86
• 참고: https://github.com/
eclipsesource/J2V8
J2V8 - TODO
• Marshalling
• JNI performance bottleneck
• Memory Management & GC
• Exception Handling
• Debugger Integration
• JSR-223 Scripting Engine
• Best Practice & Antipatterns
Rhino vs Nashorn vs V8
출처: https://ariya.io/2014/03/nashorn-the-new-rhino-on-the-block
Hello World
with V8/J2V8
V8 v8 = V8.createV8Runtime();
v8.executeScript(FileUtils.readFileToString("hello.js"));
V8Array args = new V8Array(v8).push("World");
String result = v8.executeStringFunction("greeting", args);
System.out.println(result);
args.release();
v8.release();
function greeting(name) {
return "Hello," + name + "!";
}
Hello World
with NodeJS/J2V8
NodeJS nodeJS = NodeJS.createNodeJS();
V8Object hello = nodeJS.require("./hello");
V8Array args = new
V8Array(hello.getRuntime()).push("World");
String result = hello.executeJSFunction("greeting", args);
while (nodeJS.isRunning()) {

nodeJS.handleMessage();

}
System.out.println(result);
args.release();
hello.release();
nodeJS.release();
function greeting(name) {
return "Hello," + name + "!";
}
Putting it all togethter
with J2V8
tomcatapache
webapp
(war)
MySQL
J2V8
mod_jk
AJPHTTP
JVM
server &
shared
scripts
ReactDOMServer.renderToString()
자바스크립트 기반 템플릿 엔진
JNI
npm
Putting it all togethter
with J2V8
채널 고정!
VS
I WANT TO BELIEVE
소스코드
https://github.com/iolo/spring-
template-bench
ab on my machine
• ab -n 100 -c 4
• MacBook Pro (Retina, 15-
inch, Mid 2014)
• OS X El Capitan 10.11.6
• 2.5 GHz Intel Core i7, 16GB
1600 MHz DDR3, 500GB
Apple SSD
THE TRUTH IS
OUT THERE
0
75
150
225
300
Velocity Freemarker Thymeleaf JSP ScriptTemplateView ejs handlebars J2V8TemplateView ejs
Server Only React Nashorn J2V8 Custom J2V8
THE TRUTH IS
OUT THERE
Server Only
React Custom
Nashorn J2V8 J2V8
Velocity 248.15 24.91 83.98 -
Freemarker 216.40 24.44 82.59 -
Thymeleaf 138.60 25.21 89.73 -
JSP 117.05 24.88 93.10 -
Script
TemplateView
ejs 84.40 30.10 86.39 -
handlebars 26.59 38.56 95.62 -
J2V8
TemplateView
ejs 102.65 25.37 207.70 280.90
CODE
SHOW ME THE CODE
소스코드
https://github.com/iolo/jscon-
springboard-demo 또 게시판!
ㅋㅋㅋ
디렉토리 구조
• src/main/java/
• src/main/react/
• src/main/resources/static
• src/main/resources/templates
• pom.xml
• package.json
• webpack.config.js
• target/classes/static
안봐도
비디오~
J2V8 in Action
• pom.xml - Maven Dependencies for J2V8
• J2V8TemplateView/ViewResolver/… for Spring WebMVC
• ex. ejs, handlebars, mustache, jade, …
• require()ing NPM modules
• ex. require("marked")
• webpack.config.js - client and server at once
• React Isomorphic Rendering - ReactDOMServer.renderToString()
• Async. React-Router Isomorphic Rendering - ReactRouter.match()
Time Over
…
END
HO EYO HE HUM
­ Anonymous
“Do not reinvent the wheel,
but make it perfect!”
­ Anonymous
“Reinvent the wheel,
knowing when and how.”
­ Douglas Crockford
“The good thing about reinventing
the wheel is that you can get a
round one.”
– Linus Torvalds
“Just for Fun ;)”
References
• Spring Framework: http://projects.spring.io/spring-framework/
• Node.js: https://nodejs.org
• React: https://facebook.github.io/react/
• React-Router: https://github.com/reactjs/react-router
• ScriptTemplate: https://docs.spring.io/spring/docs/current/spring-framework-reference/
html/view.html#view-script
• J2V8: https://github.com/eclipsesource/J2V8
• Rhino: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino
• Nashorn: http://openjdk.java.net/projects/nashorn/
• JSR-223: https://jcp.org/en/jsr/detail?id=223
• Isomorphic templating with Spring Boot, Nashorn and React: https://speakerdeck.com/
sdeleuze/isomorphic-templating-with-spring-boot-nashorn-and-react
• Spring mvc 서버로 Hybrid Rendering 전략 질문: https://slipp.net/questions/370
• Spring Project JIRA
• Support JavaScript Templating: https://jira.spring.io/browse/SPR-12266
• Server-side JavaScript improvements: https://jira.spring.io/browse/SPR-13508
• Remove Velocity support: https://jira.spring.io/browse/SPR-13795
• …
EVAL()의 귀환
RETURN OF THE EVAL()
Java/Spring과 Node.js의 공존 시즌3
Q&A
MAY THE **SOURCE** BE WITH YOU
Thanks
THAT’S ALL FOLKS

Java/Spring과 Node.js의 공존 시즌2

  • 1.
    Java/Spring과 Node.js의 공존시즌2 (부제: Java/Spring 전성시대에 Node.js가 살아남는 법) J2V8을 활용한 자바에 빌붙기 Dongsu Jang <iolothebard at gmail dot com>
  • 2.
  • 3.
  • 4.
    TOC • BEGIN • AS-IS •Nashorn • ScriptTemplateView • Node.js • TO-BE • J2V8 • VS • CODE • END
  • 5.
  • 6.
    개발자여, 불가능한 꿈을 꾸어라 •Just For Fun • Open Source • MSA • Polyglot • IE8 없는 세상…
  • 7.
    그러나, 리얼리스트가 되라 • 현실은자바 천국… • 스프링 전성 시대… • 봄날은 생각보다 오래 가더라… • Write Once, Ops Forever! • IE8만 없어지면 될 줄 알았지? 그래도… npm에 좋은거 많다던데…
  • 8.
    J2V8의 역습 J2V8 STRIKESBACK Java/Spring과 Node.js의 공존 시즌2
  • 9.
  • 10.
    Spring Velocity DEPRECATED 에대처하는 우리의 자세 • Thymeleaf? • 다시 JSP? • 그냥 Velocity?! • 참고: https://jira.spring.io/ browse/SPR-13235
  • 11.
    React Isomorphic Rendering 에대처하는 우리의 자세 • React? • Isomorphic? • 먹는거임? • 대세 or Hype!
  • 12.
    빌붙기의 기술 • Rhino •Nashorn • Node.js • J2V8
  • 13.
    Rhino • built-in sinceJava6 • Oldies but Goodies • Slooooow but Elegant • 참고: https:// developer.mozilla.org/en- US/docs/Mozilla/Projects/ Rhino
  • 14.
    Nashorn • built-in sinceJava8 • Fast & Easy • try `jrunscript` • JSR-223 Scripting API • 참고: http:// openjdk.java.net/projects/ nashorn/
  • 15.
    Hello World with Nashorn functiongreeting(name) { return "hello," + name + "!"; } ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval(new FileReader("hello.js")); Invocable invocable = (Invocable)engine; Object result = invocable.invokeFunction( "greeting", "World"); System.out.println(result);
  • 16.
    React Isomorphic Rendering withNashorn tomcatapache webapp (war) MySQL Nashorn mod_jk AJPHTTP JVM glue script ReactDOMServer.renderToString() 자바 기반 템플릿 엔진
  • 17.
    React Isomorphic Rendering withNashorn function renderToString(type, props) { return ReactDOMServer.renderToString(type, props); } <div id="main">${reactHtml}</div> <script src="bundle.js"></script> $.getJSON('/apis/v1/comments', function (data) {
 ReactDOM.render(<CommentList comments={ data }/>, document.getElementById('main'));
 });
  • 18.
    React Isomorphic Rendering withNashorn @RequestMapping("/comment_list") String getCommentList(Model model) { ScriptEngine engine = new ScriptEngineManager() .getEngineByName("nashorn"); engine.eval(new FileReader("polyfill.js")); engine.eval(new FileReader("react.js")); engine.eval(new FileReader("react-dom-server.js")); engine.eval(new FileReader("render.js")); Invocable invocable = (Invocable)engine; String reactHtml = (String)invocable.invokeFunction( "renderToString", "CommentList", demoService.getComments()); model.addAttribute("reactHtml", reactHtml); return "comment_list"; }
  • 19.
    ScriptTemplateView • since Spring4.2 • Easy!! • JSR-223 Scripting API • Nashorn, Rhino, JRuby, Jython, … • Template Engines • Hadlebars, Mustache, ejs, Jade and erb, Jinja2, …
  • 20.
  • 21.
    ScriptTemplateView with ejs/Nashorn @RequestMapping(“/comment_list”)
 public Stringserver(Model model) {
 model.addAttribute(“comments”, demoService.getComments());
 return "comment_list";
 } <ul>
 <% comments.forEach(function (comment) { %>
 <li>
 <h5><%= comment.content %></h5>
 <p><%= comment.author %></p>
 </li>
 <% }); %>
 </ul>
  • 22.
    ScriptTemplateView with ejs/Nashorn var _compiledTemplates= {};
 function render(template, model, url) {
 var compiledTemplate = templates[url];
 if(!_compiledTemplates[url]) {
 _compiledTemplates[url] = compiledTemplate = ejs.compile(template);
 }
 return compiledTemplate(toJsonObject(model));
 }
 function toJsonObject(javaObj) {
 var jsonObj = {};
 for (var k in javaObj) {
 if(javaObj[k] instanceof Java.type("java.lang.Iterable")) {
 jsonObj[k] = Java.from(javaObj[k]);
 } else {
 jsonObj[k] = javaObj[k];
 }
 }
 return jsonObj;
 }
  • 23.
    ScriptTemplateView with ejs/Nashorn @Configuration
 public classEjsConfig {
 @Bean
 public ScriptTemplateConfigurer scriptTemplateConfigurer() {
 ScriptTemplateConfigurer bean = new ScriptTemplateConfigurer();
 bean.setEngineName("nashorn");
 bean.setScripts(
 "/server-scripts/nashorn-polyfill.js",
 "/META-INF/resources/webjars/ejs/2.4.1/ejs-v2.4.1/ejs.min.js",
 "/server-scripts/nashorn-ejs-render.js"
 );
 bean.setRenderFunction("render");
 bean.setSharedEngine(true);
 return bean;
 }
 @Bean
 public ViewResolver scriptTemplateViewResolver() {
 ScriptTemplateViewResolver bean = new ScriptTemplateViewResolver();
 bean.setPrefix("classpath:/templates/ejs/");
 bean.setSuffix(".ejs");
 return bean;
 }
 }
  • 24.
    Node.js • Polyglot, MSAor Hype? • Fast & Easy • but Another World • npm에 좋은거 많다던데… • 참고: https://nodejs.org
  • 25.
    React Isomorphic Rendering withNode.js tomcatapache webapp (war) MySQL express mod_jk AJPHTTP JVM app.js ReactDOMServer.renderToString() 자바 기반 템플릿 엔진 HTTP Node.js HTTP
  • 26.
    React Isomorphic Rendering withNode.js var ReactDOMServer = require(‘react-dom/server’); var CommentList = require(‘comment_list’); app.get(‘/comment_list’, function (req, res, next) { db.getCommentList(function (err, data) { ReactDOMServer.renderToString(<CommentList comments={data}/>); res.send(reactHtml); }; }); @RequestMapping("/comment_list") String getCommentList(Model model) { String reactHtml = restTemplate.getForObject( "http://localhost:3000/comment_list", String.class); model.addAttribute("reactHtml", reactHtml); return "comment_list"; } <div id="main">${reactHtml}</div> <script src="bundle.js"></script>
  • 27.
  • 28.
    J2V8 • Open SourceJava bindings for V8 • Licensed under the EPL • Faaaaast Fresh! • Run on Java6 • not only V8 but also NodeJS • Linux, Windows, Mac OS X, Android ARM, Android x86 • 참고: https://github.com/ eclipsesource/J2V8
  • 29.
    J2V8 - TODO •Marshalling • JNI performance bottleneck • Memory Management & GC • Exception Handling • Debugger Integration • JSR-223 Scripting Engine • Best Practice & Antipatterns
  • 30.
    Rhino vs Nashornvs V8 출처: https://ariya.io/2014/03/nashorn-the-new-rhino-on-the-block
  • 31.
    Hello World with V8/J2V8 V8v8 = V8.createV8Runtime(); v8.executeScript(FileUtils.readFileToString("hello.js")); V8Array args = new V8Array(v8).push("World"); String result = v8.executeStringFunction("greeting", args); System.out.println(result); args.release(); v8.release(); function greeting(name) { return "Hello," + name + "!"; }
  • 32.
    Hello World with NodeJS/J2V8 NodeJSnodeJS = NodeJS.createNodeJS(); V8Object hello = nodeJS.require("./hello"); V8Array args = new V8Array(hello.getRuntime()).push("World"); String result = hello.executeJSFunction("greeting", args); while (nodeJS.isRunning()) {
 nodeJS.handleMessage();
 } System.out.println(result); args.release(); hello.release(); nodeJS.release(); function greeting(name) { return "Hello," + name + "!"; }
  • 33.
    Putting it alltogethter with J2V8 tomcatapache webapp (war) MySQL J2V8 mod_jk AJPHTTP JVM server & shared scripts ReactDOMServer.renderToString() 자바스크립트 기반 템플릿 엔진 JNI npm
  • 34.
    Putting it alltogethter with J2V8 채널 고정!
  • 35.
    VS I WANT TOBELIEVE
  • 36.
  • 37.
    ab on mymachine • ab -n 100 -c 4 • MacBook Pro (Retina, 15- inch, Mid 2014) • OS X El Capitan 10.11.6 • 2.5 GHz Intel Core i7, 16GB 1600 MHz DDR3, 500GB Apple SSD
  • 38.
    THE TRUTH IS OUTTHERE 0 75 150 225 300 Velocity Freemarker Thymeleaf JSP ScriptTemplateView ejs handlebars J2V8TemplateView ejs Server Only React Nashorn J2V8 Custom J2V8
  • 39.
    THE TRUTH IS OUTTHERE Server Only React Custom Nashorn J2V8 J2V8 Velocity 248.15 24.91 83.98 - Freemarker 216.40 24.44 82.59 - Thymeleaf 138.60 25.21 89.73 - JSP 117.05 24.88 93.10 - Script TemplateView ejs 84.40 30.10 86.39 - handlebars 26.59 38.56 95.62 - J2V8 TemplateView ejs 102.65 25.37 207.70 280.90
  • 40.
  • 41.
  • 43.
    디렉토리 구조 • src/main/java/ •src/main/react/ • src/main/resources/static • src/main/resources/templates • pom.xml • package.json • webpack.config.js • target/classes/static 안봐도 비디오~
  • 44.
    J2V8 in Action •pom.xml - Maven Dependencies for J2V8 • J2V8TemplateView/ViewResolver/… for Spring WebMVC • ex. ejs, handlebars, mustache, jade, … • require()ing NPM modules • ex. require("marked") • webpack.config.js - client and server at once • React Isomorphic Rendering - ReactDOMServer.renderToString() • Async. React-Router Isomorphic Rendering - ReactRouter.match()
  • 45.
  • 46.
  • 47.
    ­ Anonymous “Do notreinvent the wheel, but make it perfect!”
  • 48.
    ­ Anonymous “Reinvent thewheel, knowing when and how.”
  • 49.
    ­ Douglas Crockford “Thegood thing about reinventing the wheel is that you can get a round one.”
  • 50.
  • 51.
    References • Spring Framework:http://projects.spring.io/spring-framework/ • Node.js: https://nodejs.org • React: https://facebook.github.io/react/ • React-Router: https://github.com/reactjs/react-router • ScriptTemplate: https://docs.spring.io/spring/docs/current/spring-framework-reference/ html/view.html#view-script • J2V8: https://github.com/eclipsesource/J2V8 • Rhino: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino • Nashorn: http://openjdk.java.net/projects/nashorn/ • JSR-223: https://jcp.org/en/jsr/detail?id=223 • Isomorphic templating with Spring Boot, Nashorn and React: https://speakerdeck.com/ sdeleuze/isomorphic-templating-with-spring-boot-nashorn-and-react • Spring mvc 서버로 Hybrid Rendering 전략 질문: https://slipp.net/questions/370 • Spring Project JIRA • Support JavaScript Templating: https://jira.spring.io/browse/SPR-12266 • Server-side JavaScript improvements: https://jira.spring.io/browse/SPR-13508 • Remove Velocity support: https://jira.spring.io/browse/SPR-13795 • …
  • 52.
    EVAL()의 귀환 RETURN OFTHE EVAL() Java/Spring과 Node.js의 공존 시즌3
  • 53.
  • 54.