java/spring과 node.js의 공존 시즌2
TRANSCRIPT
Java/Spring과�Node.js의�공존�시즌2�(부제:�Java/Spring�전성시대에�Node.js가�살아남는�법)�
J2V8을�활용한�자바에�빌붙기
Dongsu�Jang�<iolothebard�at�gmail�dot�com>
TOC• BEGIN�
• AS-IS�
• Nashorn�
• ScriptTemplateView�
• Node.js�
• TO-BE�
• J2V8�
• VS�
• CODE�
• END
그러나,�리얼리스트가�되라
• 현실은�자바�천국…�
• 스프링�전성�시대…�
• 봄날은�생각보다�오래�가더라…�
• Write�Once,�Ops�Forever!�
• IE8만�없어지면�될�줄�알았지?
그래도…�npm에�좋은거�많다던데…
Spring�Velocity�DEPRECATED에�대처하는�우리의�자세
• Thymeleaf?�
• 다시�JSP?�
• 그냥�Velocity?!�
• 참고:�https://jira.spring.io/browse/SPR-13235
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_jkAJPHTTP
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_jkAJPHTTP
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_jkAJPHTTP
JVM
app.js
ReactDOMServer.renderToString()
자바�기반�템플릿�엔진
HTTPNode.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>
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_jkAJPHTTP
JVM
server�&�shared�scripts
ReactDOMServer.renderToString()
자바스크립트�기반�템플릿�엔진
JNI
npm
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 OnlyReact 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
소스코드
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()
�Douglas�Crockford�
“The�good�thing�about�reinventing�the�wheel�is�that�you�can�get�a�
round�one.”�
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�
• …