Java web development is notorious for its long deployment times. Java’s modify-build-deploy-test cycle is a huge disappoint to developers used to TurboGears, Ruby-on-Rails, or even PHP’s “save-and-see-changes-immediately” work flow.
One important goal of SlimWeb is to shorten these cycles, so that you can spend more time writing and testing your application, and less time waiting for your web app to be redeployed. Using SlimWeb’s default configuration you can already achieve redeployment times of under a second, which is OK by Java standards, but still slow compared to the competition.
Fortunately, SlimWeb’s redeployment times can be shortened in many, although not necessarily trivial, ways.
In this post I’ll try and describe how I got my application to redeploy in less than a hundred milliseconds!
What is involved in a SlimWeb app redeployment?
- Checking and gathering of external dependencies
- Compiling your code
- Preparing the Java Web Application folder tree
- Zipping the web application tree into a .WAR file
- Deploying the app to a web container (Tomcat, Jetty, etc)
This is what more or less happens when you type ‘ant deploy’ in your project’s folder.
The default SlimWeb configuration already optimizes this process to a significant extent.
- The external jars gathering happens only the first time you build your app. Once you have all the external dependencies and they are up-to-date, the first step of the build process does nothing.
- Building is incremental, so only the modified files are rebuilt as you would expect. However, if you use Eclipse, you can use it’s built-in compiler that compiles code as you type. When you hit ctrl+s to save your source file, Eclipse has already compiled it and simply saves it to disk, eliminating the need for the ant task to do any compilation itself.
- Every SlimWeb project has a ‘/WebContent’ folder that serves as the root of the web app tree. When you edit JSP, TAG, JS, CSS or image files, you edit them directly in this folder, so no copying is required, but, more importantly, no redeployment is required, when these files are modified. Redeployment only happens when external dependencies (which are automatically copied to ‘/WebContent/WEB-INF/lib’) and/or resource and .class files (copied to ‘/WebContent/WEB-INF/classes’) are modified.
- During development you can skip the .WAR archive. You can deploy the exploded WebContent folder directly in your web container. On Linux and MacOS you can create a symlink in TOMCAT_HOME/webapps. On non-Unix platforms you’ll need to edit your web container’s XML configuration files. Refer to your container’s manual for details.
- Your web container will by default reload a web app if a special file’s modified date changes. For Tomcat that special file is ‘/WebContent/WEB-INF/web.xml’. For Jetty it’s the context file for your app, something like ‘JETTY_HOME/contexts/yourapp.xml’.
SlimWeb will automatically determine when a redeployment is needed (only if resource, class or jar files were modified) and touch the special file, triggering a redeployment in your web container.
This step takes the longest time in the entire modify-build-deploy cycle. See below for some hacks to speed it up.
That’s how the default setup works and achieves redeployment times of a second or less (that’s when resource, .class or .jar files are modified).
Note that when you modify stuff outside of ‘/WebContent/WEB-INF/’ no redeployment occurs and changes are visible immediately.
Now let’s do some hacking
DISCLAIMER: The hints that follow may cut your redeployment times dramatically, but are not for the faint of heart! Unless you’re able and willing to modify your web container configuration, your app’s build scripts, and your Eclipse project’s configuration, you should wait for SlimWeb 2.0 where some of these ideas may find their way into the framework itself, and hopefully become a little bit more developer-friendly.
You can greatly speed up reload times within your web container by moving some .jar files from ‘/WebContent/WEB-INF/lib’ to your web container’s lib folder. For Tomcat that’s ‘TOMCAT_HOME/lib’, and for Jetty it’s ‘JETTY_HOME/lib’
The more jars you move this way, the faster your app will redeploy. When you move a file to your web container’s lib folder, make sure your app’s ant script no longer copies it to ‘/WebContainer/WEB-INF/lib’. You’ll need some ant knowledge to do this. The smaller your WEB-INF/lib folder, the faster your app will redeploy.
WARNING Only do this for external jar files. Do not attempt this trick for your own .jar files.
HINT This works best for “runtime dependencies”, i.e. jars that are only needed at run-time, and not at compile-time. The best candidates are your JDBC driver, and the JPA implementation jars. You can also do this for your “compile-time” deps, but you’ll need to further edit your ant script, so that it can find the compile-time jars which are no longer in ‘WEB-INF/lib’, but also you will need to configure one or more User Libraries in Eclipse, so Eclipse itself can find them. By default both ant and Eclipse look for compile-time jars in ‘WEB-INF/lib’ so be careful when you move stuff away from that folder.
The Magic redeployment hack
If you’re using Linux (the reload.py script requires pyinotify, which is only available on Linux!) you can go one step further and disable the ant part of the build process altogether, relying on the Eclipse compiler only.
To do this you can follow these steps:
- Run ant build at least one so that dependencies are initialized correctly, resource files are converted as needed, etc.
- Go to ‘your_project/build’ and rename the ‘classes’ folder to ‘classes.bak’
- In the same folder create the following symlink: ln -s ../WebContent/WEB-INF/classes
- Launch the magic reload script: SLIMWEB_HOME/bin/reload.py
- Edit a source file in Eclipse, and hit ctrl+s.
On a Core2 machine, your app should automatically reload and be ready for testing 50 msec later