Better J2EEing with Spring

Pages: 1, 2, 3

Spring as a Standardized Locator Pattern

I've always thought of the Service Locator pattern as a staple of good J2EE etiquette. For those of you not familiar with this idiom, it goes something like this: Generally we think of a typical J2EE application as being composed of tiers. Typically there is a Web tier, a services tier (EJB, JMS, WS, WLS control), and of course the database. Often, some mechanics are involved in "finding" services that are required to complete a request. The Service Locator pattern suggests that it is a good idea to wrap these mechanics in some sort of factory class that hides the complexity of producing or finding a given service. This cuts down on the proliferation of JNDI or other service production code that does nothing but muddy the Web tier action class. Prior to the advent of Spring, this was commonly accomplished by the tried-and-true Singleton class. The Singleton/Locator/Factory pattern goes something like this:

Figure 2
Figure 2. Sequence diagram of the Locator pattern

This is a vast improvement over a proliferation JNDI lookup code scattered throughout your Web controller code. Instead it is neatly hidden within the collaborating classes inside the factory. We can improve this idiom with Spring. Incidentally, this solution will have applicability for EJBs, Web services, asynchronous JMS calls and even for WLS Control-based services. This variant of the Locator Pattern as implemented by Spring allows for a bit of abstraction and homogeneity among your business services. In other words, your Web controller developers really shouldn't care what kind of service they are talking to, a concept similar to "WLS Controls" but a bit more universal.

An IoC framework vastly improves the utility of this pattern and virtually does away with complicated, specialty, singleton code to get it accomplished. By borrowing from concepts that have been introduced in the previous example, we can build a very powerful and ubiquitous Service Locator pattern with virtually no extra code. Implementing this begins with a simple mandate that Web action developers should deal exclusively with things that implement interfaces. By and large we already do this with EJB programming, but there is nothing that says services that the Web actions developers deal with must be implemented in terms of EJB. They could easily be plain Java objects or Web services. The main point is that services should be programmed in terms of interfaces (so implementations can be swapped in and swapped out) and the runtime configuration can be handled by Spring.

The thing that makes Spring so well suited to the Service Locator pattern is the ability to treat different types of objects more or less uniformly. With a little planning and liberal use of IoC, we can handle most objects, regardless of their nature (EJB, POJO, and so on) in a more or less universal manner and all without having a proliferation of Singleton factory classes. This makes programming in the Web tier easier and more flexible.

Let's look first at an example of how this pattern would be applied in the case of EJB. We all are aware that using EJB is probably the most complicated approach due to what it takes to get a live reference to an EJB. It is recommended in the Spring world that EJB interfaces extend a non-EJB-specific business interface. This serves two purposes: It keeps the two interfaces automatically in sync, and it also helps to keep business services swappable to non-EJB implementations for testing or stubbing purposes. We can rely on Spring's intrinsic utilities to locate and create the EJB instance and at the same time handle all the heavy lifting for us. The way this is configured is as follows:

<bean id="myBizServiceRef"
         class="org.springframework.ejb.access.
         LocalStatelessSessionProxyFactoryBean">
  <property name="jndiName">
    <value>myBizComponent</value>
  </property>
  <property name="businessInterface">
    <value>
      yourco.project.biz.MyBizInterface
    </value>
  </property>
</bean>

You can then retrieve the bean and start working on it like this:

MyBizInterface myService = bf.getBean("myBizServiceRef");

This returns an object that Spring dynamically creates for us and that wraps the underlying target, in this case, a local EJB instance. This is nice because it completely hides the fact that we are dealing with an EJB. Instead we interact with a proxied object that implements the plain business interface. Spring has thoughtfully and dynamically generated this object for us around the "real" business object. The object that is wrapped is of course the local EJB that Spring has located and retrieved a reference for. Moreover, you'll notice that this form of code is identical to that used earlier to retrieve the tempSensor object.

So what if we change our mind and want our business component to be implemented via a plain Java object, or perhaps we're testing and we want to replace the heavyweight EJB with a stubbed object that returns "canned" responses? Using IoC and Spring it's pretty easy to accomplish this by changing the Spring context file. We simply replace the wiring of the EJB proxy with something a little more conventional as we saw in the first Spring example:

<bean id="myBizServiceRef"
  class="yourco.project.biz.MyStubbedBizService">
</bean>

Notice I've only changed the details of what gets handed back by the Spring framework, and not the bean id. The net result is that the resolution of the business object does not change; it looks exactly the same as it did before:

MyBizInterface myService =
  bf.getBean("myBizServiceRef");

The biggest difference obviously is that the object that implements the business interface now is backed by a plain Java object (POJO) and is simply a stubbed version of the interface. This is extremely handy for unit testing or altering the nature of business services with little impact on client code.

Uh Oh! Using Spring to Standardize Exceptions

One really great thing that Spring has managed to accomplish is to "templatize" blocks of code. Nowhere is this more evident than with straight JDBC programming. We've all written code that does something like the following:

  • Create a database connection, hopefully from a pool somewhere.
  • Construct a query string and submit.
  • Iterate over the results and marshal the data into a domain object.
  • Handle the prolific exceptions that can occur at various stages.
  • Make sure we remember to code a finally block that closes the connection.

What tends to happen is that this code gets more or less "boilerplated" all over the place. This is generally bad, not only because of a proliferation of unneeded code, but because things have a tendency to be missed, such as the all-important closing of the connection, which, if not done, can cause leaks in your data source pool.

Although I'm sure we've all written this type of "boilerplate" code many times, seeing it again paints an interesting and stark contrast between Spring's methodology and a straight JDBC implementation. The "traditional" JDBC implementation might look something like this:

Connection con = null;
try
{
  String url = "jdbc://blah.blah.blah;";
  con = myDataSource().getConnection();
  Statement stmt = con.createStatement();
  String query = "SELECT TYPE FROM SENSORS";
  ResultSet rs = stmt.executeQuery(query);
  while (rs.next()) {
    String s = rs.getString("TYPE);
    logger.debug(s + "   " + n);
  }
} catch (SQLException ex)
{
  logger.error("SQL ERROR!",ex);
}
finally
{
  con.close();
}

A few comments regarding this approach. First, it works! There is absolutely nothing wrong with this code. It will connect to a database and get the data you want from the 'SENSOR' table. The basic problem with this approach stems from a lack of abstraction. In a large application you will have to cut and paste this chunk of code over and over again, or at least something similar. The larger problem is relying on programmers to do the "right thing." As we all know, it is imperative to have a finally statement that closes the database regardless of the outcome of the database operations. Sometimes we forget to do the right thing. I'm as guilty as anyone!

It would be easy enough to write a small framework to fix this problem. I'm sure we've all done that too, but why not let Spring handle it for us? I doubt I could come up with a cleaner, more elegant solution. Let's look at how the Spring framework handles this boilerplate JDBC scenario.

Spring supports a variety of templates for JDBC, Hibernate, JDO, and iBatis. Templates take the concept of boilerplating and transform it into a legitimate programming idiom. For example, the following snippet of code encapsulates the constituent steps outlined above:

DataSource ds = (DataSource) bf.getBean("myDataSource");
JdbcTemplate temp = new JdbcTemplate(ds);
List sensorList = temp.query("select sensor.type FROM sensors",
  new RowMapper() {
     public Object mapRow(ResultSet rs, int rowNum)
       throws SQLException;
        return rs.getString(1);
     }
  });

This handy bit of code addresses all the tedium of JDBC programming and represents the idea of boilerplating as mentioned earlier. Notice the use of Spring's IoC to look up the data source for this query. Spring also favors the use of unchecked exceptions over checked exceptions; therefore many checked JDBC exceptions get remapped into a generally more useful and friendly unchecked exception hierarchy. Configuring this data source in Spring's context file might look something like this:

<bean id="myDataSource"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName">
    <value>org.gjt.mm.mysql.Driver</value>
  </property>
  <property name="url">
    <value>jdbc:mysql://romulus/sensors</value>
  </property>
  <property name="username">
    <value>heater</value>
  </property>
  <property name="password">
    <value>hotshot</value>
  </property>
</bean>

In this case, we've configured a basic data source from the Apache commons toolkit. But we are not limited to using just this. We could switch the configuration to use a data source configured and stowed in JNDI. Spring has utility and IoC functionality to configure and hand back objects stored in JNDI. If, for example, you wanted to configure and use a data source associated with a JNDI context, you would enter in the following stanza, replacing the previous data source configuration:

<bean id="myDataSource"
  class="org.springframework.jndi.
  JndiObjectFactoryBean">
  <property name="tempSensorDS">
    <value>ConnectionFactory</value>
  </property>
</bean>

This highlights the flexibility that Spring brings to the table with respect to testing. Your code can run "in the container" (look up a data source from JNDI), and, with a little change, "outside the container" too.

Pages: 1, 2, 3

Next Page ยป