How do you develop a web application in Java?
After each change, how do you run it and test it? How long does the application take and the container
restart ?
I happened to see different options: from a complete reassembly of the WAR file to the use of plug-ins for IDEs like MyEclipse, WTP and “connectors” for servlet-contractors. Some of them have obvious shortcomings, others quite work - but there is a simpler way!
Launch
This way of development allows you to
easily and
flexibly configure the application
with the minimum redeploy time . You just need to write one simple Java class with a main method that will launch the Jetty server immediately with the necessary applications (the so-called
Embedded Mode ).
')
Here is the minimal configuration of the launcher:
import org.mortbay.jetty.*; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.jetty.webapp.WebAppContext; public class Launcher { public static void main(String[] args) throws Exception { Server server = new Server(); Connector connector = new SelectChannelConnector(); connector.setPort(8080); server.addConnector(connector); WebAppContext root = new WebAppContext("root/src/main/webapp", "/"); WebAppContext reports = new WebAppContext("reports/src/main/webapp", "/reports"); WebAppContext petclinic = new WebAppContext("petclinic/src/main/webapp", "/petclinic"); server.setHandlers(new Handler[]{root, reports, petclinic}); server.start(); } }
This code starts the server (servlet container) listening on port 8080, with three web applications that code is taken
directly from the project folders (
root/src/main/webapp
,
reports/src/main/webapp
and
petclinic/src/main/webapp
), that is, any changes to the files
take effect immediately , without the need to rebuild and
redo anything .
Understandably, adding new methods will have to be restarted, but in this case, the restart happens as quickly as possible, literally within a second (of course, if your applications do not do something complicated at startup). If you
add a JRebel to this, it will be chocolate.
That's the whole trick.
Surely in
production you are not using Jetty, but something like Tomcat, JBoss or WebLogic. It doesn’t matter, we’re talking about development, where speed, stability, etc. unimportant, but important is the ease of setup, launch speed and redeploy. And here Embedded Jetty is what the doctor ordered.
You can just run this main class from your favorite IDE, debug, test, restart; and no plugins are needed, no need to look for configuration files, no need to dig into XMLs. All settings at hand. This is life!
For launching in the minimum configuration, just three jar files are enough: servlet-api.jar , jetty.jar , jetty-util.jar .
[UPD] As suggested by
kblcuk , the above launch code only works for Jetty 6 version. Starting with the seventh version of Jetty, the names of the packages and classes
were changed from org.mortbay.jetty. * To org.eclipse.jetty. *, So you have to correct import.
Tuning
Consider some additional features that may be useful depending on the project.
Class loaders
The code above loads the classes and dependencies of all web applications in a single loader (ClassLoader). If for some reason it is important for you that web applications have different sets of classes and dependencies (jars), this can also be done by adding a bit of code:
WebAppContext petclinic = new WebAppContext("petclinic/src/main/webapp", "/petclinic"); WebAppClassLoader classLoader = new WebAppClassLoader(petclinic); classLoader.addClassPath("petclinic-core/target/classes"); classLoader.addClassPath("petclinic-services/target/classes"); petclinic.setClassLoader(classLoader);
I used it myself when I had to run many web applications at once, each with its own (conflicting) dependencies. Very simple, very convenient.
Jsp
Old-timers remember that in unforgettable times such a thing as JSP was often used to generate HTML. If your JSP project is also used, you will need to add a few more dependencies:
eclipse-jdtcore.jar ,
jsp-api-2.1-glassfish.jar ,
jsp-2.1-glassfish.jar
JDBC Resource Configuration
Perhaps there is a simpler solution, but I have earned this option:
import import javax.naming.InitialContext; import com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean; static void setupDataSources() { System.setProperty("java.naming.factory.initial", "org.mortbay.naming.InitialContextFactory"); AtomikosNonXADataSourceBean dataSource = new AtomikosNonXADataSourceBean(); dataSource.setUniqueResourceName("jdbc/portal"); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); dataSource.setUser("myusername"); dataSource.setPassword("mypassword"); dataSource.setMaxPoolSize(10); new InitialContext().createSubcontext("jdbc").bind("portal", dataSource); }
To do this, you will additionally need some more dependencies: transactions.jar , jetty-naming.jar , transactions-api.jar , transactions-jta.jar , transactions-jdbc.jar , atomikos-util.jar
Could this still be a little more automated?
Can. But only if necessary.
If your database address or password changes frequently, you may want to read them from some file. It's possible. But is it worth it? The main thing is that all the settings are concentrated in one file, and what kind of file is it - java-class or * .properties - does it matter?
If the list of web applications is constantly changing, it may make sense to write a plug-in for Eclipse or IDEA that would run Jetty with all the projects that are currently in Eclipse. One such plugin is described
here - it finds all projects that have a web.xml file, and adds other projects to them in the classpath.
Minuses
For the sake of objectivity, I will try to name some of the pitfalls that lurk in this approach.
- (Imaginary minus) Jetty container is inferior in performance to Tomcat, JBoss, Resin, etc.
Nonsense. We are now talking about development - here the performance is completely unimportant.
By the way, it is still a question whether it is inferior.
- (Imaginary minus) Jetty container is unstable / sometimes crashes / contains memory leaks.
Nonsense. See previous paragraph.
- If your application uses some specific features of a particular container (especially WebLogic or Oracle AS), then it will not work on Jetty, of course.
Probably nothing can be done about it. I can only advise you not to use such features so that your application does not depend on the container.
- Sometimes it happens that your application works fine on your computer in Embedded Jetty mode, but crashes when assembled in war and installed on another server.
This, though rarely, happens. In particular, an error may occur due to class loaders or jar versions.
Alternatives
For the sake of interest, I will list alternative ways to develop Java web applications with my subjective assessment.
- Full reassembly of the WAR file and copying to Tomcat / webapps.
The most reliable and slowest solution. Imagine waiting 1-15 minutes after every CSS change! No, thank you.
Minus: terribly long.
Minus: debug will have to be configured separately (remote debug). Suppose it is not very difficult, but still extra effort. - Myeclipse
Paid IDE based on Eclipse. When compiling a project, it copies all resources into a separate folder - it worked awfully long for me. Also, I still have unpleasant memories from the settings. - Eclipse WTP (Web Tools Platform) - a free, but heavy plugin for Eclipse
I tried several times, but could not adjust it as I need.
Plus: can work with several different containers (Tomcat, JBoss, etc.)
[UPD] However, here Akvel tells how he painlessly uses the Eclipse WTP.
- Application server integrations
analogue of Eclipse WTP, available only in the paid version Intellij IDEA.
Minus: paid. - Jrebel
In addition to its main task, JRebel allows you to configure ClassPath applications directly from projects.
Minus: JRebel paid.
Plus: if your employer forks him, JRebel can greatly simplify and speed up the work of the developer. - Play! framework
Able to run the application directly from the project and reload the modified code on the fly. Very comfortably.
Minus: you are limited to one framework, which has its own characteristics and limitations. - Run jetty run
Plugin for Eclipse, allowing you to run Jetty with the application directly from the project. In essence, it does exactly the same thing as described in this article.
Plus: contains all the necessary jar'y, you do not have to download anything further, except for the plug-in itself.
Minus: can run only one project.
Minus: can not configure a database connection. We have to do it anyway with our hands. - [UPD] Jetty Maven plugin
As 1nd1go tells you , if Maven is used in your project, you can launch web applications with the command " mvn jetty:run
".
Plus: if you use the Maven plugin in your IDE , you can run this command directly from the IDE; you can debug as jetty plugin runs in the same process as maven.
Minus: you are tied to the build system (maven) and to the IDE. - [UPD] Jetty Gradle plugin
If Gradle is used in your project, you can launch web applications with the " gradle jettyRun
" gradle jettyRun
.
Plus: this command directly from the IDE (even without any plug-ins), while you can debug.
Minus: you are tied to the assembly system (gradle). - [UPD] Sysdeo Eclipse Tomcat Launcher plugin
As helions8 suggests, there is a good Sysdeo Tomcat launcher plugin for Eclipse that allows you to combine the context of tomkata and the project, so you don’t need to pick up a war-file and put it to the container, every css, html and other js is edited right away, on hot. In most cases, hot replace works. Essentially, this plugin does the same thing as our Launcher.
Minus: you are tied to Eclipse.
Minus: requires more fuss. It is necessary to download Tomcat yourself, and to create some kind of “tomcat project” - in general, it is quite a good tool, but it is easier to launch. - [UPD] Spring source tool suite
As alexeygrigorev suggests, for Eclipse, there is a Spring source tool suite plugin that has a built-in “tomkat” that can redraw when saving files
Minus: you are tied to Eclipse and STS.
It remains to add that in the
embedded mode, you can run not only Jetty, but also
Tomcat ,
Glassfish , etc. The specific container is unimportant, the principle is important: no lengthy reassembly, installation, decompression and configuration. Everything starts quickly and simply from one class.
I myself have been developing web applications in this way for several years and advise everyone else. This way you will spend less time fussing around assembling and installing and will be able to focus on the actual development.
Run it!