ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button O'Reilly Book Excerpts: Better, Faster, Lighter Java

Demonstrating Spring's Finesse

by and Justin Gehtland

Author's note: In this excerpt from Chapter 8 of our book, Better, Faster, Lighter Java, we look at an example of an enterprise web application using the Spring framework. While Hibernate provided a single service, the Spring framework provides an efficient way to build and assemble Java applications, with abstractions for many services. Although it supports many services, Spring stays focused and clean with excellent layering and encapsulation. Like EJB, the centerpiece for Spring is a container, and like EJB, the Spring framework provides access to core J2EE services. But that's about as far as any similarities go. Here's a metaphor.

Related Reading

Better, Faster, Lighter Java
By Justin Gehtland

I love to kayak and spend a lot of time teaching kayaking skills. One of my specialties is teaching students how to roll an upside-down kayak in white water. One day, I was teaching this skill to a muscle-bound hulk and a dainty little 97lb woman. While I talked through the technique on dry land, Meathead stared into the distance, disinterested. The woman focused well and wanted to practice the foundation techniques over and over. Within a half an hour, she hit her first roll incredibly well, while he was just thrashing about, whipping the calm water into fine white foam. He didn't come close until his third session. In sessions to come, she relied on her technique to improve quickly; he relied on strength, and floundered. When it was time to put the skills into practice, she rolled while he swam. Programmers, take note: it's usually better to solve problems with simplicity and finesse rather than muscle.

Pet Store: A Counter-Example

The J2EE Pet Store application is an infamous programming example gone bad. It taught thousands of J2EE developers to build poorly designed, poor-performing code. It was also the center of a benchmarking controversy. A respected consulting company called The Middleware Company worked on a benchmark comparing J2EE with Microsoft's .NET platform. As a foundation for the benchmark, they chose the J2EE version of Pet Store. Though they worked hard to tune it, the J2EE version lost badly to the Microsoft .NET version and many criticized the design. I don't intend to lay any blame for this fiasco. Instead, I offer a different interpretation. It's my firm opinion that J2EE, especially EJB, makes it hard to develop clean, high-performance code. Put another way, the Pet Store benchmark was a symptom of a larger problem.

After the benchmarking uproar, a number of people showed how to implement Pet Store with easier, simpler technologies. One of the strongest and simplest implementations, by Clinton Begin, used a DAO framework called iBatis instead of full entity beans. Rod Johnson's team converted that application to Spring, and now distributes it with the Spring framework. Here are some of the details:

  • The Spring jPetStore application comes with Spring Versions M4 and beyond.

  • It's a data-driven application with a JDBC DAO layer.

  • It provides alternative frontends for Struts, and the Spring MVC framework.

  • It provides two different models. The simplest uses a single database and simple JDBC transactions. The other uses JTA transaction management across multiple data stores.

In the following sections, I'll work through the version of the application with the MVC web frontend and simple transactions across one database. I'll focus on the domain model, the single-database DAO layer, simple transactions, and the Spring MVC frontend. Outstanding resources are available at the Spring web site for those who want to dive deeper.

The Configuration

When learning a Spring application, start with the configuration file; it shows you the major beans and how the application fits together. A Spring configuration file defines the beans in an application context. Think of the context as a convenient collection of named resources for an application.

Many J2EE applications keep track of application resources such as connections and the like with singletons. When you think about it, a singleton used in this way is not much different from a global variable; many Java developers lean on this crutch too often. J2EE's alternative is a directory service called JNDI, but it's overkill for many common uses. Spring, instead, uses an application context. Initially, you specify it in a simple XML file, although you can extend Spring to accept other kinds of configuration as well. Here are some of the things that might go into an application context:

Data sources

A Java class that manages connections, usually in a pool.

DAO layers

If your applications use a database, you probably want to isolate the database access to one layer, the DAO. You can access this layer through the application context.

Persistence managers

Every persistence framework has an object or factory that the application uses to access its features. With Hibernate, it's the session and the session factory. With JDO, it's the persistence manager factory and persistence manager.

Transaction policies

You can explicitly declare the methods that you want to participate in transactions and the transaction manager that you want to use to enforce that strategy.

Transaction managers

There are many different transaction management strategies within J2EE. For single database applications, Spring lets you use the database's transaction management. For multiple databases or transaction sources, Spring allows JTA instead. You can keep the transaction manager in the application context.

Validation logic

The Spring framework uses a validation framework similar to Struts. Spring lets you configure validation logic like any other business component.

Views and controllers

The Spring framework lets you specify the controllers for a view and helps you configure the navigation path through them.

The jPetStore application uses the Spring application context for a data source, the DAO layer, and a transaction strategy. You define what goes into a context within an XML document that lists a series of beans. Each XML configuration file will have a <beans> heading, followed by a series of <bean> components, and a </beans> footer, like this:

<beans>

<bean id="MyFirstBean" class="package.MyFirstBeanClass">
  <property name="myField" ref local="MySecondBean"/>
</bean>

<bean id="MySecondBean" class="package.MySecondBeanClass">
</bean>

</beans>

These are the beans that make up an application context. They represent the top-level beans of an application. (They may create other objects or beans that do not appear in the configuration file.) In this case, you create two beans named MyFirstBean and MySecondBean. Then, you wire them together by specifying MySecondBean as the value for the field myField. When Spring starts, it creates both objects and sets the value of myField. You have access to both of these objects by name whenever you need them through the application context.

Let's look at a more concrete example. The jPetStore application has three configuration files for the business logic, the data layer, and the user interface, as in Figure 8-2. A separate Spring configuration file describes each one.

Figure 8-2
Figure 8-2. The jPetStore application has Spring application contexts to match its three distinct layers

These configuration files specify the context for the domain model, the data layer, and the presentation layer. Example 8-1 shows part of the application context for the business logic of the jPetStore application. Note that I've shortened the package name from org.springframework.samples.jpetstore... to jpetstore for simplicity.

Example 8-1. applicationContext.xml

<beans>
[1] <bean id="accountValidator" class="jpetstore.domain.logic.AccountValidator"/>
[2] <bean id="orderValidator" class="jpetstore.domain.logic.OrderValidator"/>
[3] <bean id="petStoreTarget" class="jpetstore.domain.logic.PetStoreImpl">
[4]   <property name="AccountDao"><ref bean="accountDao"/></property>
      <property name="categoryDao"><ref bean="categoryDao"/></property>
      <property name="productDao"><ref bean="productDao"/></property>
      <property name="itemDao"><ref bean="itemDao"/></property>
      <property name="orderDao"><ref bean="orderDao"/></property>
    </bean>
  
[5] <bean id="petStore" 
   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager"><ref bean="transactionManager"/></property>
      <property name="target"><ref bean="petStoreTarget"/></property>
      <property name="transactionAttributes">
        <props>
          <prop key="insert*">PROPAGATION_REQUIRED</prop>
          <prop key="update*">PROPAGATION_REQUIRED</prop>
          <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
        </props>
      </property>
    </bean>

  </beans>

Here's an explanation of the annotated lines:

[1] Business logic. This section (which includes all bold code) has the core business logic. Validation and the domain model are both considered business components.

[2] Validators. This is the validator for Order. Spring calls it whenever a user submits the Order form and routes to the error page or an order completion page, as required.

[3] Core business implementation. This class contains the core implementation for the persistent domain model. It contains all of the DAO objects that you'll see below.

[4] Properties. Each of your beans has individual properties that may refer to beans you define elsewhere. In this case, the bean properties are individual DAO. Each of these beans is defined in another Spring configuration file.

[5] Transaction declarations. This bean specifies the transaction strategy for the application. In this case, the application uses a transaction manager specified in another Spring configuration file. It declares the methods that should be propagated as transactions. For example, all methods beginning with insert should be propagated as transactions.

In short, this configuration file serves as the glue that holds the business logic of the application together. In the file, you see some references to beans that are not in the configuration file itself, such as the DAO objects. Later on, you'll see two other configuration files that define some of the missing beans. One specifies the data access objects with the transaction manager. The other specifies the beans needed by the user interface. It's often better to break configuration files into separate layers, allowing you to configure individual layers as needed. For example, you may want to change strategies for your user interface (say, from Spring MVC web to Struts) or for data access (say, from DAO with one database to DAO spanning two databases with JTA transactions).

If you want to instantiate a bean from your XML context file, it's easy. For example, in order to access a bean called myCustomer of type Customer from a file called context.xml, take the following three steps:

  1. Get an input stream for the XML file with your configuration:

    InputStream stream = getClass( ).getResourceAsStream("context.xml");
  2. Create a new Spring bean factory using the input stream:

    XmlBeanFactory beanFactory = new XmlBeanFactory(stream);
  3. Use the factory to create one of the objects defined in your .xml file:

    Customer cust = (Customer)beanFactory.getBean(myCustomer);

Or, if you want Spring to initialize a context and then grab, for example, your session façade, you'd use code like this:

protected static final String CONTEXT_FILE = "WEB-INF/applicationContext.xml";
Biz biz;  // session façade

FileSystemXmlApplicationContext ctx =
   new FileSystemXmlApplicationContext(CONTEXT_FILE);
biz = (Biz) ctx.getBean("biz");

It's often better to let go of that control. Usually, you won't have to access the application context directly. The framework does that for you. For example, if you're using servlets, the Spring framework provides a context for each servlet and a catch-all context for servlets. From there, you can usually get the appropriate context information, as you'll see later. Now that you've seen a configuration file representing the jPetStore application, it's time to see how to build the individual elements.

The Domain Model

In keeping with the principles in the book, the foundation of the application is the transparent domain model in Figure 8-3. The domain model contains the business relationships of objects that represent the real world. Pet Store is made up of carts and orders that contain items.

Figure 8-3
Figure 8-3. The center of an application is the domain model

The application represents a simple pet store. It consists of a shopping cart containing cart items, which feeds an order containing line items. Items consist of products organized into categories. Each object is a transparent business object implemented as a Java bean with some properties and some business methods. Example 8-2 shows a CartItem. I've eliminated the imports and package detail, for brevity.

Example 8-2. CartItem.java

[1] public class CartItem implements Serializable {       

    /*Private Fields*/

    private Item item;
    private int quantity;
    private boolean inStock;

    /*JavaBeans Properties*/

[2] public boolean isInStock() { return inStock; }
    public void setInStock(boolean inStock) { this.inStock = inStock; }

    public Item getItem( ) { return item; }
    public void setItem(Item item) {
      this.item = item;
    }

    public int getQuantity( ) { return quantity; }
    public void setQuantity(int quantity) {
      this.quantity = quantity;
    }

[3] public double getTotalPrice() {
      if (item != null) {
        return item.getListPrice( ) * quantity;
      }
      else {
        return 0;
      }
    }

    /*Public methods*/

    public void incrementQuantity( ) {
       quantity++;
    }

  }

Here's what the annotations mean:

[1] The Spring framework does not force components to inherit from a Spring class. They are fully transparent, and can live outside of the container for testing purposes, or if Spring would some day prove inadequate.

[2] Each field is wrapped with get and set methods, so that Spring can configure them through Java reflection. (Spring can alternatively configure them through constructors.)

[3] Unlike many EJB applications, it's often helpful to include business domain logic within the domain model.

I call this model passive. It's invoked entirely by objects outside of its domain and has coupling only to other objects within the domain. Notice that it is not merely a value object, although it does have private properties and public fields It has business methods to calculate the total price and increment the quantity. This design makes this business object easy to understand and reuse, even though the overall design may evolve. As we move into persistence, you'll see other parts of the model as well.

Next week in the conclusion to this two-part series on Spring, excerpted from Better, Faster, Lighter Java, the authors will take you through adding persistence to their Pet Store example, and take a look at the area of presentation logic in the Spring framework.

Justin Gehtland is a programmer, author, mentor and instructor, focusing on real-world software applications.


Return to ONJava.com.




0