n my 15 years as a software professional I've never seen a software stack as unproductivenot to mention as verbose or complicatedas J2EE, despite its enterprise-grade features. Every single J2EE project I have ever worked on ended the same way: me looking at long lines of Ant build scripts constantly rebuilding WARs and EARs (starting/stopping/re-deploying, and so on). No developer should spend half of his or her day waiting for even the simplest of code changes to be redeployed by an Ant script.
When my current company evaluated the future maintenance of our J2EE-based applications, it became clear that some of the core components needed a wholesale rewrite. Choosing Spring over Java EE 5 was an obvious choice (more on that later), but choosing the appropriate web container took a bit more time. After struggling with some of the "bugginess" of Eclipse WTP (especially when it comes to re-deploying project code into the web container), a simpler, leaner alternative emerged: using Spring with embedded Jetty.
Using embedded Jetty also has a few huge productivity boosts, namely:
The JVM's hot code replacement in particular has been a tremendous boost to our day-to-day productivity. I haven't seen a single Ant build in weeks. In those rare cases when I actually needed to restart the application (e.g., upon changing some Spring configuration), it took no more than 3-4 seconds.
Also, most of the best open-source Java libraries (such as Apache CXF or Apache Active MQ) now come with Spring integration out of the box. This gives you the flexibility to choose whichever best-of-breed components you need, instead of being stuck with the typical monolithic Java EE container's all-or-nothing approach.
Moreover, Spring sub-projects such as Spring Security or Spring BlazeDS are so far ahead of the Java EE stack's offerings (or have no equivalents in the stack at all), that anyone selecting Java EE as the basis for new application development really needs to reconsider that choice.
| What You Need |
|---|
| Jetty 6 (the latest stable release) |
| Spring Framework 2.5 |
| Eclipse IDE for Java Developers |
| Apache CXF (to add web services) |
| Apache ActiveMQ (to add messaging) |
Your main server project should look something like Figure 1 after being set up. Remember to make all the third-party JARs available to other projects by exporting them in the project's build properties configuration (see Figure 2).
![]() Figure 1. A Configured Embedded Jetty Server Project: Your main server project should look something like this. |
![]() Figure 2. Exported Jetty and Spring JARs: Make all the third-party JARs available to other projects. |
Here is the minimal code required for a typical embedded Jetty start up:
Server jetty = new Server();
String[] configFiles = {"etc/jetty.xml"};
for(String configFile : configFiles) {
XmlConfiguration configuration = new XmlConfiguration(new File(configFile).toURI().toURL());
configuration.configure(jetty);
}
jetty.start();
That's it! The best part is that running this code makes Jetty start up in less than one second (on my machine). Starting and stopping your application is much faster than re-deploying a WAR could ever be, and it makes enterprise/web development in Java as easy as developing a regular application.
Open up your browser and point it to localhost:8080 and you should see a message from Jetty informing you that it's running. However, it won't have any contexts configured. That comes next.
Begin by adding a new Java project to your workspace, called simply MyApp. Besides the default src folder for Java classes, also add a new folder called web, which will contain all the web content (e.g., JSPs, web config files, and so on). Because this is a regular Java project and not an Eclipse WTP dynamic web project, no special plugins are required. This makes the whole approach easy to reproduce in other IDEs such as NetBeans or IntelliJ.
Under the web folder, create the WEB-INF folder. In it, you will add the following standard web.xml file, which registers Spring:
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
Next, add a Spring beans.xml file in the WEB-INF folder. To avoid excessive XML configuration, configure it to use annotations for business components:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="com.devx.myapp" />
</beans>
Obviously, replace the base package com.devx.myapp with one that is specific to your application.
Last but not least, go back to your server project and explicitly configure your web application:
Server jetty = new Server();
String[] configFiles = {"etc/jetty.xml"};
for(String configFile : configFiles) {
XmlConfiguration configuration = new XmlConfiguration(new File(configFile).toURI().toURL());
configuration.configure(jetty);
}
//configure your web application
WebAppContext appContext = new WebAppContext();
appContext.setContextPath("/myapp");
File rd = new File("./");
File warPath = new File(rd,"../MyApp/web");
appContext.setWar(warPath.getAbsolutePath());
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{ appContext, new DefaultHandler()});
jetty.setHandler(handlers);
jetty.start();
The section starting with WebAppContext configures MyApp under the /myapp context. When you run the main server class, you should see output like this in the console:
2009-06-21 07:47:13.585::INFO: Logging to STDERR via org.mortbay.log.StdErrLog
2009-06-21 07:47:13.672::INFO: Statistics on = false for SelectChannelConnector @ 0.0.0.0:8080
2009-06-21 07:47:13.756::INFO: jetty-6.1.3
2009-06-21 07:47:13.962:/myapp:INFO: Initializing Spring root WebApplicationContext
21-Jun-2009 7:47:13 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
21-Jun-2009 7:47:14 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.web.context.support.XmlWebApplicationContext@1950198:
display name [Root WebApplicationContext]; startup date [Sun Jun 21 07:47:13 EDT 2009]; root of context hierarchy
21-Jun-2009 7:47:14 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from ServletContext resource [/WEB-INF/beans.xml]
21-Jun-2009 7:47:14 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@1950198]:
org.springframework.beans.factory.support.DefaultListableBeanFactory@5d391d
21-Jun-2009 7:47:14 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5d391d:
defining beans [org.springframework.context.annotation.internalCommonAnnotationProcessor,
org.springframework.context.annotation.internalAutowiredAnnotationProcessor,
org.springframework.context.annotation.internalRequiredAnnotationProcessor]; root of factory hierarchy
21-Jun-2009 7:47:14 AM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 384 ms
2009-06-21 07:47:14.419::INFO: Started SelectChannelConnector @ 0.0.0.0:8080
Even with a configured, Spring-enabled web application now being served, start-up time is still extremely fast, as this line indicates:
INFO: Root WebApplicationContext: initialization completed in 384 ms
With this in place, your daily productivity will not suffer from the constant overhead of re-deploying your WAR and EARs when your web or business logic changes. Also, unlike the often buggy hot-deploy features of Eclipse WTP, this approach works 100 percent of the time.
Bear in mind one small gotcha: You must remember to add the MainServer project as a dependency to your application (see Figure 3) so that it can access all the Spring classes it exports. When configured, your application project should look like the one in Figure 4.
Figure 3. Adding a Dependency on the Server Project: Add the MainServer project as a dependency to your application. |
![]() Figure 4. A Configured Web Application Project: When configured, your application project should look like this. |
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
}
In order to use the component in a service using dependency injection, all you need is the @Autowired annotation:
@Service
public class MyService {
@Autowired(required=true)
private MyComponent myComponent;
}
The only entries in the Spring beans.xml file are those that usually require external configuration anyway (e.g., JDBC entries for datasources), but you can configure all the business logic using annotations, which is much easier.
However, as stated previously, Spring's benefits go far beyond its dependency injection features. Its extremely useful template classes (e.g., JdbcTemplate) are what really give you that extra boost in day-to-day productivity. If you're new to Spring, you certainly should explore them.
If you need message-driven POJOs in your app, I recommend you integrate Apache ActiveMQ. It too is Spring-enabled out of the box. The Spring messaging documentation has ample examples of how to post and consume messages using message-driven POJOs
If you want to use Log4J in your projects, just add the Apache Log4J libraries to the main server and place the standard log4j.properties file in the server's /etc folder.
Although you used embedded Jetty for development in the example presented here, nothing is stopping you from compiling your application project (i.e., MyApp in the example) as a typical WAR and deploying it to a standalone Jetty installation for the QA/integration phase of your project. You can still reap the benefits of embedded Jetty during your day-to-day development.
| DevX is a division of Internet.com. © Copyright 2010 Internet.com. All Rights Reserved. Legal Notices |