Secrets of lightweight development success, Part 3: The emergence of Spring

Behind the hype

Lightweight containers provide a means for organizing the glue code for an application. The Spring framework is the predominant lightweight container. Spring contains a lightweight container, an aspect-oriented programming framework, and glue code that makes it easy to integrate hundreds of open source frameworks.

Share:

Bruce Tate (bruce.tate@j2life.com), President, RapidRed

Bruce TateBruce Tate is a father, mountain biker, and kayaker in Austin, Texas. He's the author of three best-selling Java books, including the Jolt winner Better, Faster, Lighter Java. He recently released Spring: A Developer's Notebook. He spent 13 years at IBM and is now the founder of the J2Life, LLC, consultancy, where he specializes in lightweight development strategies and architectures based on Java technology and Ruby.



14 June 2005

In 2003, three mountain bikers and I screamed down the ledge-filled trail called Forrest Ridge. It had just reopened, without fanfare, so most of Austin, Texas, didn't know. Throughout that autumn, we had been running this gem alone. On this day, we had to dodge more than 20 other bikers on a short stretch of trail. The secret was out.

Although the public discovery of our wonderful trail wasn't a good thing for my friends and me, it is a good thing when your open source trail gets discovered. You can find resources more easily, get fixes more quickly, and in general take advantage of the additional community. Now, Spring has now been discovered. It's among the most important open source projects, and it's well on its way to achieving Hibernate-like success as a major player both in and out of enterprise environments. This article shows you why Spring is so significant to lightweight development.

What is Spring?

If you're an enterprise developer, Spring can make your life easier. But what is it? With a framework this comprehensive, that's not an easy question to answer. Basically, Spring is a lightweight container. With Spring, you can program with plain old Java™ objects (POJOs), resolve dependencies between them with dependency injection, and attach services to them with aspect-oriented programming (AOP).

Spring also provides some glue code that makes it easier to use Java 2 Platform, Enterprise Edition (J2EE) services, such as Java Transaction API (JTA), for transactions, Remote Method Invocation (RMI) for remoting, Java Management Extensions (JMX) for management, or Java Data Objects (JDO) for persistence. Spring also provides glue code for open source frameworks, such as Hibernate, Tapestry, Struts, and JavaServer Faces (JSF). Notice that some of the frameworks compete, and that's OK: Spring doesn't try to pick a winner.

Some services are available with Spring. For example, Web Flow makes handling the flow between Web pages easier. Similarly, Web MVC provides a Model-View-Controller (MVC) architecture for Web-based applications that is similar to Struts.

So, Spring casts a broad shadow. Like Enterprise JavaBean (EJB) technology, Spring's container lets you consume enterprise services. Unlike EJB 1.x and 2.x, however, you put JavaBeans -- not some proprietary component -- into the container. In another separation from EJB, Spring doesn't lock you into just a few standardized services. Instead, it lets you choose from hundreds of services, or even build your own.

To me, Spring is the most important open source project in the Java community. It's helping redefine J2EE. Partially as a result of the pressure from innovations in Spring, the EJB 3 expert group built a specification describing an interface more like Spring's than EJB 2.x. I can easily imagine a scenario in which Spring becomes as ubiquitous as Struts for enterprise development. To help you understand why Spring is so important, let's peel back the layers.


The core container

First, look at how Spring works. I won't post full examples because you can find dozens of Spring tutorials. Instead, I point you to the sample application for my latest book and post snippets of that example to show what Spring can do for you.

The application simply maintains a list of bikes for an operation called RentaBike. Spring serves as the backbone for the application. Spring's main container, the context, holds references to all the main layers of the application and services. The main layers of the application are a database, a persistence framework, a database access object, and user interface (UI) controller and view layers.

The Spring context for the application is simply a list of beans the application uses. The beans don't have to rely on any Spring interfaces, but sometimes, I choose to rely on Spring to provide some of the repetitive glue code that holds the application together. In the context, you'll find at least five types of metadata:

  • Configuration -- Because the container already has to do some configuration to handle dependency injection (covered in Secrets of lightweight development success, Part 2: How to lighten up your containers), it makes sense to handle other configuration here, too, so that you have a convenient, consistent strategy.
  • Major layers of the application -- In the RentaBike application, I expose a Data Access Object (DAO) layer, a controller layer, and a view layer (see Listing 1). I choose to wrap the DAO in an interface, so I can switch my data access layer to use different persistence strategies.
  • External dependencies -- For instance, my DAO needs a data source. Spring injects the resources my DAO needs, such as data sources, and platform-specific configuration, such as Hibernate's session factory.
  • Transparent services -- One of the biggest benefits of EJB technology was declarative transactions. You had to pay a lot to get them because you were forced to use an EJB interface and heavyweight EJB containers. Spring lets you configure only the services you need and apply them to POJOs. In Spring, you can make any method transactional.
  • Data -- Often, message data, information about application flow, and test data might also be placed in the application context.
Listing 1. A partial context for RentaBike
<beans>
 
 <bean id="rentaBike" class="com.springbook.JDBCRentABike">
   <property name="storeName">
     <value>Bruce's Bikes</value> 
   </property>
   <property name="dataSource">
     <ref bean="dataSource" /> 
   </property>
 </bean>
 


  <bean id="bikesController" class="com.springbook.BikesController">
    <property name="facade">
      <ref bean="rentaBike" /> 
    </property>
 


  </bean>
    <bean id="dataSource"
              class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName">
      <value>com.mysql.jdbc.Driver</value> 
    </property>
    <property name="url">
      <value>jdbc:mysql://localhost/bikestore</value> 
    </property>
    <property name="username">
      <value>bikestore</value> 
    </property>
  </bean>
 
</beans>

If you look closely at a context, you'll notice that it's made up of beans. That's important because earlier J2EE containers forced you to use a given API, especially EJB. Each bean has a set of properties. Some are strings and other primitive values. Some are beans, like the data source required by the rentaBikebean. You don't have to implement an API, like the interface for EJB session beans. You just list beans and their properties. Some of the properties satisfy dependencies. You've got better transparency, so you can run your beans outside the container or move your application to other containers, should the need arise.

Contexts for testing

You may wind up putting other types of beans in the context, too. For example, it often makes sense to use the context to populate simple test data, or application flow, in the context. In Spring: A Developer's Notebook, we drive the first implementations of our UI with a stub that uses an array list instead of a database. Say I've got a database table with names and e-mail addresses. I can build a simple stub that has an array list as a property, then implement some simple data access methods quickly, as Listing 2 shows.

Listing 2. A testing stub to replace a database
public class StubEmailDirectory {
    private List people;
    public List getPeople() {
        return people;
    }
    public void setPeople(List people) {
        this.people = people;
    }
 
    public String findEmail(String name) {
        Person p = findPerson(name);
        if (p==null) {
             return null;
        }
        return p.getEmail();
    }
.
public Person findPerson(String name) {
        if (people==null) {
            return null;
        }
        int size = people.size();
        for(int i=0;i<size;i++) {
            Person p=(Person)people.get(i);
            if(p.getName().equals(name)) {
                 return p;
            }
        }
        return null;
    }
}

I can then populate it from the context, as Listing 3 shows.

Listing 3. Test data in a context
<beans>
 
<bean id="bruce" class="j2life.bus.Person">
        <property name="name">
            <value>Bruce</value>
        </property>
        <property name="email">
            <value>bruce.t@j2life.com
            </value>
        </property>
    </bean>
 
<bean id="maggie" class="j2life.bus.Person">
        <property name="name">
            <value>Maggie</value>
        </property>
        <property name="email">
            <value>maggie.t@j2life.com
            </value>
        </property>
    </bean>
    <bean id="emails" class="j2life.bus.StubEmailDirectory">
        <property name="people">
            <list>
                <ref bean="bruce"/>
                <ref bean="maggie"/>
            </list>
        </property>
    </bean>
</beans>

When you think about it, drawing test data from a context often makes sense. To make test cases repeatable and verifiable, you can draw unpredictable data, such as system times and random numbers, from a context instead of from the services. Spring's context makes testing much easier because you can configure applications in different ways for production and testing.

The foundation of Spring is the container, and it's important. But the container doesn't even come close to telling the whole story.


Leverage

Like me, world-champion cyclist Lance Armstrong is from Austin, Texas. I've enjoyed watching him bike through the years, in part because he gets more leverage out of each turn of the pedals than anyone else in the world. I look for opportunities for additional leverage with everything I do. Spring gives me better leverage by providing glue code that takes away the cumbersome repetitive resource management, configuration, and grunt work similar across my applications.

Take persistence. Hibernate is a beautiful persistence alternative. But like all persistence frameworks, it forces you to manage some low-level details I'd prefer to do without. Listing 4 shows an example of a Hibernate application without Spring.

Listing 4. Hibernate without Spring
// Configuration code
Configuration config = new Configuration( );
config.addClass(Bike.class).addClass(Customer.class).
addClass(Reservation.class);
SessionFactory mySessionFactory = Configuration.buildSessionFactory( );

 
public List getBikesOldWay( ) throws Exception {
  List bikes = null;
  Session s = null;
  try {
    s = mySessionFactory.openSession( );
    bikes = s.find("from Bike");
  }catch (Exception ex) {
    //handle exception gracefully
  }finally {
    s.close( );
  }
  return bikes;
}

Listing 5 shows a similar example, but with Spring.

Listing 5. Hibernate with Spring
public List getBikes( ) {
  return getHibernateTemplate( ).find("from Bike");
}

Look at the Hibernate template as the methods that implement things you'd want to do to a session. Notice especially what you don't see. You don't have to worry about transactions because Spring lets you configure them declaratively. You don't have to worry about managing resources because that code is in the template. Spring always closes the session, so you don't have to. You don't have to handle exceptions at this level because Spring translates them to a common set of unchecked exceptions. I like unchecked exceptions because I can choose to expose them at the appropriate level of the architecture. You provide only the bare minimum needed to tell Hibernate what to do. Spring handles the rest. That's leverage.

Spring provides leverage in other ways, too. By providing the same kind of glue code for other services, Spring eases my burden as an application programmer. I don't have to repeat myself nearly as often. I can use remoting, transactions, security, persistence, and MVC code much more easily because Spring does the heavy lifting.

I'd like to point out that there is a down side here. When I decide to use Spring's glue code instead of my own, I do build a dependency on the Spring framework. Most of the time, I'm willing to pay that price.


AOP

In Part 2 in this series, you learned that AOP can let you attach services to a POJO, giving you much better transparency. With AOP, you can strip many cross-cutting concerns right out of your code. So, why wouldn't you just download an AOP framework and use it directly?

In reality, some teams do. It's been my experience that technologies are ready far before we have the wisdom to use them. When I see AOP in the hands of intermediate and novice programmers, I imagine kids with power tools. Face it: When it comes to AOP, most of us are still kids. As it was with object-oriented programming, we've got to spend a little time accumulating the wisdom it takes to use AOP effectively.

Spring gives me the ability to use AOP with training wheels. I can take some prepackaged aspects and look at examples that show well-defined scenarios, thereby getting much of the benefit of AOP without all the risk. In fact, you've often seen similar strategies in the past. The Ada programming language allowed encapsulation, but only limited inheritance. Early windowing environments like the Microsoft® Windows® programming model internally had Window objects, events that looked like Smalltalk messages, and even hierarchies, but exposed a procedural programming model. I believe the same strategy is important for AOP.


Spring's significance

For those who use it, Spring is revolutionary. These simple ideas lead to huge consequences:

  • Spring effectively opens up the enterprise services container. You no longer have to be a slave to the API or services a container provides. You can use the Spring context to manage prepackaged services, snap in third-party services, or write your own.
  • Spring represents a huge step forward in testability. With Spring, you can use dependency injection to work mock objects into hard-to-reach places, run objects outside the container (because they are POJOs), and even use the container to serve unpredictable data.
  • Spring's glue code makes it much easier to plug in enterprise services with very little programming. You write less code, so you have to read less code for maintenance or extension.
  • Spring represents an open source project that's redefining the way in which Java's commercial groups build their software. The influence of Spring on the latest EJB specification is undeniable, and it's important.

Spring has become one of the pillars of enterprise lightweight development. The resources below can show you how to get started or dig deeper into Spring. In the next article in this series, I'll introduce you to a few persistence alternatives for lightweight development.

May your favorite open source trail be discovered, too.

Resources

Learn

  • Check out the Spring framework.
  • Better, Faster, Lighter Java, by Bruce A. Tate and Justin Gehtland, (O'Reilly, 2004) provides a good overview of lightweight development.
  • Read Spring: A Developer's Notebook, by Bruce A. Tate and Justin Gehtland, (O'Reilly, 2005) to get started quickly with Spring. If you want to get it, make sure you use the online programming examples to follow along. Also, be sure to get the reprint (second printing or beyond) because it takes care of a bunch of important errors.
  • Pro Spring provides a more comprehensive treatment of Spring.
  • Object-relation mapping without the container, by Richard Hightower, shows you how to use Spring persistence with Hibernate.
  • AOP@Work: AOP tools comparison, Part 1, by Mik Kersten, for a treatment of AOP, a lightweight technique that can give you much better transparency.
  • "Lightweight development" is a huge topic, and developers throw the term around so often that it's hard to tell what it means. "Secrets of lightweight development success, Part 1: Core principles and philosophies" introduces the core principles and philosophies behind the movement.
  • Heavyweight architectures, such as Enterprise Java Beans can be overkill for everyday problems. "Secrets of lightweight development success, Part 2: How to lighten up your containers" introduces lightweight containers and explains how they can provide the services your business needs without tying you to a given programming model.
  • In Part 4 of the series, three popular containers are compared: Spring, HiveMind, and PicoContainer.
  • Lightweight development works best with a lightweight process, but it can be tough to get a conservative company to adopt agile methodologies. Learn how you can propose and promote lightweight processes in your organization in Part 5 of this series.
  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.

Get products and technologies

  • Innovate your next open source development project with IBM trial software, available for download or on DVD.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=85587
ArticleTitle=Secrets of lightweight development success, Part 3: The emergence of Spring
publish-date=06142005