** How different is the development productivity of Spring Boot-based applications compared to developing legacy web applications? ** **
With a web application "EasyBuggy" based on a little old technology and its clone (exactly the same function) Compare a Spring Boot-based "Easy Buggy Boot" with the following numbers that affect development productivity: I tried it.
--Time to build
By the way, the main differences in configuration are as follows.
Difference | EasyBuggy | EasyBuggy Boot |
---|---|---|
Base technology | Servlet 3.0.1 | Spring Boot 1.5.6 (Servlet 3.0.1) |
Presentation layer | unused(Some JSP 2.2 + JSTL 1.2) | Thymeleaf 2.1.5 (Some JSP 2.3 + JSTL 1.2) |
Java container | Apache Tomcat/7.0.37 | Apache Tomcat/8.5.16 |
DB client/server | JDBC / Derby 10.8.3.0 | Spring JDBC 4.3.9 / Derby 10.12.1.1 (For Java 7), Or 10.13.1.1 (For Java 8) |
LDAP client/server | Apache DS Client API 1.0.0 / Server 1.5.5 | Spring LDAP 2.3.1 / unboundid-ldapsdk 3.2.1 |
JavaMail 1.5.1 | JavaMail 1.5.1 (Java Mail introduced by Spring Boot Mail 1.5.Override 6) | |
Development tools | None | Spring Boot Developer Tools 1.5.6 |
Java | Supports Java 6 and above | Supports Java 7 and above |
First, the average build time. The result is as follows.
EasyBuggy
About 6 seconds
$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building easybuggy 1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
・ ・ ・(Omitted because it is long)・ ・ ・
[INFO] --- tomcat7-maven-plugin:2.1:exec-war-only (tomcat-run) @ easybuggy ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.847s
[INFO] Finished at: Thu Aug 31 23:28:55 JST 2017
[INFO] Final Memory: 36M/220M
[INFO] ------------------------------------------------------------------------
EasyBuggy Boot
About 12 seconds
$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building easybuggy4sb 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
・ ・ ・(Omitted because it is long)・ ・ ・
[INFO] --- spring-boot-maven-plugin:1.5.6.RELEASE:repackage (default) @ easybuggy4sb ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.448s
[INFO] Finished at: Thu Aug 31 23:26:55 JST 2017
[INFO] Final Memory: 26M/242M
[INFO] ------------------------------------------------------------------------
The former is faster by more than double the difference.
By the way, the environment used for verification is CentOS 6.9 on VMWare, CPU 4 cores (Intel® Xeon® X5680 @ 3.33GHz), and memory 4GB. All dependent libraries have been downloaded locally.
The average startup time is as follows.
EasyBuggy
About 3 seconds
$ java -jar easybuggy.jar
8 31, 2017 2:44:56 pm org.apache.coyote.AbstractProtocol init
information: Initializing ProtocolHandler ["http-bio-8080"]
8 31, 2017 2:44:56 pm org.apache.catalina.core.StandardService startInternal
information: Starting service Tomcat
8 31, 2017 2:44:56 pm org.apache.catalina.core.StandardEngine startInternal
information: Starting Servlet Engine: Apache Tomcat/7.0.37
8 31, 2017 2:44:59 pm org.apache.coyote.AbstractProtocol start
information: Starting ProtocolHandler ["http-bio-8080"]
EasyBuggy Boot
About 15 seconds (about 9 seconds for mvn spring-boot: run
)
$ java -jar ROOT.war
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/Users/ktamura/git/easybuggy4sb/target/ROOT.war!/WEB-INF/lib/logback-classic-1.1.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/Users/ktamura/git/easybuggy4sb/target/ROOT.war!/WEB-INF/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.6.RELEASE)
2017-08-31 15:08:46.454 INFO 5460 --- [ main] o.t.e.Easybuggy4sbApplication : Starting Easybuggy4sbApplication v1.0.0-SNAPSHOT on ktamura-PC with PID 5460 (C:\Users\ktamura\git\easybuggy4sb\target\ROOT.war started by k
tamura in C:\Users\ktamura\git\easybuggy4sb)
・ ・ ・(Omitted because it is long)・ ・ ・
2017-08-31 15:09:01.198 INFO 5460 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2017-08-31 15:09:01.273 INFO 5460 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-08-31 15:09:01.276 INFO 5460 --- [ main] o.t.e.Easybuggy4sbApplication : Started Easybuggy4sbApplication in 15.253 seconds (JVM running for 15.81)
EasyBuggy starts up very quickly, so it feels slow even in 15 seconds. Looking at the EasyBuggy Boot log, there isn't an extremely time-consuming process, so there may not be much room for improvement. I think that the startup time of Spring Boot will take at least that much.
This result is the result of the built-in Tomcat, but the result is almost the same even when the war file is deployed to the non-built-in Tomcat.
However, EasyBuggy Boot takes about 9 seconds when started with the mvn spring-boot: run
command. I compared the logs of both to see why this difference occurs, but it seems that there is no big difference in the processing being executed, and I did not know the clear reason.
The average time from modifying the source code to being able to check the operation is as follows.
EasyBuggy
About 15 seconds
EasyBuggy uses the mvn install
command to create a jar file and start it all at once. It takes about 15 seconds to restart, including the time required for this and the stop. Of course, the JVM hot swap will reflect the fixes while debugging, so it won't take much time in actual development ... (and even faster with JRebel).
EasyBuggy Boot
About 3 seconds
2017-09-01 12:04:55.414 INFO 2800 --- [ Thread-104] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@27231264: startup date [Fri Sep 01 12:04:21 JST 2017]; root of context hierarchy
2017-09-01 12:04:55.417 INFO 2800 --- [ Thread-104] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4274ec33: startup date [Fri Sep 01 12:04:23 JST 2017]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@27231264
2017-09-01 12:04:55.532 INFO 2800 --- [ Thread-104] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
2017-09-01 12:04:55.537 WARN 2800 --- [ Thread-104] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'inMemoryDatabaseShutdownExecutor': java.sql.SQLSyntaxErrorException: Syntax error: Encountered "SHUTDOWN" at line 1, column 1.
2017-09-01 12:04:55.538 INFO 2800 --- [ Thread-104] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.6.RELEASE)
・ ・ ・(Omitted because it is long)・ ・ ・
2017-09-01 12:04:57.895 INFO 2800 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8081 (http)
2017-09-01 12:04:57.897 INFO 2800 --- [ restartedMain] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2017-09-01 12:04:57.923 INFO 2800 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-09-01 12:04:57.925 INFO 2800 --- [ restartedMain] o.t.e.Easybuggy4sbApplication : Started Easybuggy4sbApplication in 2.125 seconds (JVM running for 828.681)
EasyBuggy Boot has introduced Spring Boot Developer Tools 1.5.6, so the fixes are reflected immediately and you can develop with almost no waiting. This sense of speed is very comfortable.
Let's compare the number of lines in the source code.
EasyBuggy
Type td> | Blank line td> | Comment line td> | Code td> | Number of files td> |
Java | 838 | 359 | 4881 | 98 |
JSP | 11 | 10 | 810 | 6 |
XML | 5 | 0 | 47 | 2 |
HTML | 2 | 0 | 35 | 7 |
properties | 71 | 325 | 799 | 6 |
Total td> | 927 | 694 | 6572 | 119 |
EasyBuggy Boot
Type td> | Blank line td> | Comment line td> | Code td> | Number of files td> |
Java | 663 | 131 | 3500 | 92 |
HTML | 8 | 39 | 1034 | 46 |
JSP | 0 | 4 | 149 | 2 |
XML | 0 | 1 | 32 | 4 |
SQL | 0 | 0 | 18 | 3 |
JSON | 0 | 0 | 17 | 1 |
DTD | 0 | 0 | 3 | 1 |
LDIF | 0 | 5 | 46 | 1 |
properties | 86 | 321 | 830 | 4 |
Total td> | 757 | 501 | 5629 | 154 |
While the number of lines of EasyBuggy source code is 6,572, EasyBuggy Boot is 5,629, so using Spring Boot can reduce the number by about 15%. There is a difference of about 1.3 times in the number of files, but I think that it is because EasyBuggy did not separate the screen and logic into separate files (JSP etc.) (* I wanted to explain one bug in one file, so I made it like that I made it).
How has the readability of the source code changed? For the following functions
The source code of each is as follows.
EasyBuggy
XSSServlet.java
package org.t246osslab.easybuggy.vulnerabilities;
import java.io.IOException;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.t246osslab.easybuggy.core.utils.HTTPResponseCreator;
import org.t246osslab.easybuggy.core.utils.MessageUtils;
@SuppressWarnings("serial")
@WebServlet(urlPatterns = { "/xss" })
public class XSSServlet extends HttpServlet {
private static final Logger log = LoggerFactory.getLogger(XSSServlet.class);
@Override
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String string = req.getParameter("string");
Locale locale = req.getLocale();
StringBuilder bodyHtml = new StringBuilder();
bodyHtml.append("<form action=\"xss\" method=\"post\">");
bodyHtml.append(MessageUtils.getMsg("description.reverse.string", locale));
bodyHtml.append("<br><br>");
bodyHtml.append(MessageUtils.getMsg("label.string", locale) + ": ");
bodyHtml.append("<input type=\"text\" name=\"string\" size=\"100\" maxlength=\"100\">");
bodyHtml.append("<br><br>");
bodyHtml.append("<input type=\"submit\" value=\"" + MessageUtils.getMsg("label.submit", locale) + "\">");
bodyHtml.append("<br><br>");
if (!StringUtils.isBlank(string)) {
// Reverse the given string
String reversedName = StringUtils.reverse(string);
bodyHtml.append(MessageUtils.getMsg("label.reversed.string", locale) + " : "
+ reversedName);
} else {
bodyHtml.append(MessageUtils.getMsg("msg.enter.string", locale));
}
bodyHtml.append("<br><br>");
bodyHtml.append(MessageUtils.getInfoMsg("msg.note.xss", locale));
bodyHtml.append("</form>");
HTTPResponseCreator.createSimpleResponse(req, res, MessageUtils.getMsg("title.xss.page", locale),
bodyHtml.toString());
}
}
EasyBuggy Boot
xss.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" th:with="lang=${#locale.language}" th:lang="${lang}">
<div th:replace="head"></div>
<body style="margin-left: 20px; margin-right: 20px;">
<div th:replace="header"></div>
<form action="xss" method="post">
<p th:text="#{description.reverse.string}" /><br />
<label th:text="#{label.string}"></label><span>: </span>
<input type="text" name="string" size="100" maxlength="100" /><br /><br />
<input type="submit" /><br /><br />
<p th:utext="${msg}" /><br />
<div class="alert alert-info" role="alert">
<span class="glyphicon glyphicon-info-sign" th:utext="#{msg.note.xss}"></span>
</div>
</form>
</body>
</html>
XSSController.java
package org.t246osslab.easybuggy4sb.vulnerabilities;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class XSSController {
@Autowired
MessageSource msg;
@RequestMapping(value = "/xss")
public ModelAndView process(@RequestParam(value = "string", required = false) String string, ModelAndView mav,
Locale locale) {
mav.setViewName("xss");
mav.addObject("title", msg.getMessage("title.xss.page", null, locale));
if (!StringUtils.isBlank(string)) {
// Reverse the given string
String reversedName = StringUtils.reverse(string);
mav.addObject("msg", msg.getMessage("label.reversed.string", null, locale) + " : " + reversedName);
} else {
mav.addObject("msg", msg.getMessage("msg.enter.string", null, locale));
}
return mav;
}
}
Since the function itself is simple, there may not be a big difference in readability, but the latter is easier for programmers and designers to share the work. Of course, if you use JSP for the former, it will be close to that.
Recommended Posts