Architecting Applications with Spring


Let's now look at how a typical application using Spring is organized, and the kind of architecture Spring promotes and facilitates.

Important 

Spring is designed to facilitate architectural flexibility. For example, if you wish to switch from Hibernate to JDO or vice versa (or from either to the forthcoming JSR- 220 POJO persistence API), using Spring and following recommended practice can make that easier. Similarly, you can defer the choice as to whether to use EJB for a certain piece of functionality, confident that you won't need to modify existing code if a particular service ends up implemented by an EJB rather than a POJO.

Let's now look at how a typical Spring architecture looks in practice, from top to bottom.

Note 

The architecture described here is referred to as the "Lightweight container architecture" in Chapter 3 of J2EE without EJB (Johnson/Hoeller, Wrox, 2004). As such an architecture is based on OO best practice, rather than Spring, it can be implemented without Spring. However, Spring is ideally suited to making such architectures succeed.

The Big Picture

Figure 1-1 illustrates the architectural layers in a typical Spring application. Although this describes a web application, the concepts apply to most logically tiered applications in general.

image from book
Figure 1-1

Let's summarize each layer and its responsibilities, beginning closest to the database or other enterprise resources:

  • Presentation layer: This is most likely to be a web tier. This layer should be as thin as possible. It should be possible to have alternative presentation layers — such as a web tier or remote web services facade — on a single, well-designed middle tier.

  • Business services layer: This is responsible for transactional boundaries and providing an entry point for operations on the system as a whole. This layer should have no knowledge of presentation concerns, and should be reusable.

  • DAO interface layer: This is a layer of interfaces independent of any data access technology that is used to find and persist persistent objects. This layer effectively consists of Strategy interfaces for the Business services layer. This layer should not contain business logic. Implementations of these interfaces will normally use an O/R mapping technology or Spring's JDBC abstraction.

  • Persistent domain objects: These model real objects or concepts such as a bank account.

  • Databases and legacy systems: By far the most common case is a single RDBMS. However, there may be multiple databases, or a mix of databases and other transactional or non-transactional legacy systems or other enterprise resources. The same fundamental architecture is applicable in either case. This is often referred to as the EIS (Enterprise Information System) tier.

In a J2EE application, all layers except the EIS tier will run in the application server or web container. Domain objects will typically be passed up to the presentation layer, which will display data they contain, but not modify them, which will occur only within the transactional boundaries defined by the business services layer. Thus there is no need for distinct Transfer Objects, as used in traditional J2EE architecture.

In the following sections we'll discuss each of these layers in turn, beginning closest to the database.

Important 

Spring aims to decouple architectural layers, so that each layer can be modified as far as possible without impacting other layers. No layer is aware of the concerns of the layer above; as far as possible, dependency is purely on the layer immediately below. Dependency between layers is normally in the form of interfaces, ensuring that coupling is as loose as possible.

Persistence and Integration

Getting data access right is crucial for success, and Spring provides rich services in this area.

Database

Most J2EE (or Java applications) work with a relational database. Ultimately data access will be accomplished using JDBC. However, most Spring users find that they do not use the JDBC API directly.

Spring encourages a decoupling of business objects from persistence technology using a layer of interfaces.

Data Access Objects

In keeping with the philosophy that it is better to program to interfaces than classes, Spring encourages the use of data access interfaces between the service layer and whatever persistence API the application(or that part of it) uses. However, as the term Data Access Object (DAO) is widely used, we continue to use it.

DAOs encapsulate access to persistent domain objects, and provide the ability to persist transient objects and update existing objects.

By using a distinct layer of DAO objects, and accessing them through interfaces, we ensure that service objects are decoupled from the persistence API. This has many benefits. Not only is it possible to switch between persistence tools more easily, but it makes the code more coherent through separation of concerns and greatly simplifies testing (a particularly important concern when using an agile process). Imagine a business service method that processes a set of orders: If the set of orders is obtained through a method on a DAO interface, it is trivial to supply a test DAO in a JUnit test that supplies an empty set or a particular set of orders, or throws an exception — all without going near a database.

DAO implementations will be made available to objects using them using Dependency Injection, with both service objects and DAO instances configured using the Spring IoC container.

DAO interfaces will typically contain the following kinds of methods:

  • Finder methods: These locate persistent objects for use by the business services layer.

  • Persist or save methods: These make transient objects persistent.

  • Delete methods: These remove the representation of objects from the persistent store.

  • Count or other aggregate function methods: These return the results of operations that are more efficient to implement using database functionality than by iterating over Java objects.

Less commonly, DAO interfaces may contain bulk update methods.

Note 

While Spring encourages the use of the term "DAO" for such interfaces, they could equally well be called "repositories," as they are similar to the Repository pattern described in Eric Evans' Domain- Driven Design (Addison-Wesley, 2003).

The following interface shows some of the methods on a typical DAO interface:

public interface ReminderDao {       public Collection             findRequestsEligibleForReminder()  throws DataAccessException;       void persist(Reminder reminder) throws DataAccessException;       void countOutstandingRequests() throws DataAccessException;     }

Note that all methods can throw Spring's DataAccessException or subclasses, thus wholly decoupling callers from the persistence technology in use. The DAO tier interfaces have become truly persistence technology agnostic.

This interface might be implemented using Hibernate, with Spring's convenience classes, as follows (some methods omitted for brevity):

public class HibernateReminderDao extends HibernateDaoSupport implements ReminderDao {       public Collection findRequestsEligibleForReminder()                             throws DataAccessException {           getHibernateTemplate().find("from Request r where            r.something = 1");   }       public void persist(Reminder reminder)                            throws DataAccessException {           getHibernateTemplate().saveOrUpdate(reminder);   } }

An implementation using another O/R mapping tool, such as TopLink, would be conceptually almost identical, although naturally using a different underlying API (but also benefiting from Spring conveniences). Following the DAO pattern as facilitated by Spring and illustrated in Spring sample applications such as the Spring PetStore ensures a consistent architectural approach, whatever the chosen persistence API.

Our DAO interface could be implemented using Spring's JDBC abstraction as follows:

public class JdbcReminderDao extends JdbcDaoSupport                                         implements ReminderDao {       public Collection findRequestsEligibleForReminder()                                 throws DataAccessException {          return getJdbcTemplate().query("SELECT NAME, DATE, ... " +                                 " FROM REQUEST WHERE SOMETHING = 1",                 new RowMapper() {                 public Object mapRow(ResultSet rs, int rowNum) throws SQLException {                         Request r = new Request();                         r.setName(rs.getString("NAME"));                         r.setDate(rs.getDate("DATE"));                         return r;                 }          });   }       public int countRequestsEligibleForReminder()                                     throws DataAccessException {          return getJdbcTemplate.queryForInt("SELECT COUNT(*) FROM ...");   } }

Don't worry if you don't understand the details at this point: we'll discuss Spring's persistence services in detail in Chapter 5, "DAO Support and JDBC Framework." However, you should be able to see how Spring eliminates boilerplate code, meaning that you need to write only code that actually does something.

Important 

Although they are typically used with relational databases and O/R mapping frameworks or JDBC code underneath, Spring DAO interfaces are not specific to RDBMS access. Spring's DAO exception hierarchy is completely independent of any persistence technology, so users have contributed support for LDAP and other technologies, and some users have implemented connectivity to products such as Documentum, within the consistent Spring data access architectural approach.

Persistent Domain Objects

Persistent domain objects are objects that model your domain, such as a bank account object. They are persisted, most often using an O/R mapping layer.

Note that the desire to isolate service objects from persistence APIs does not mean that persistent objects should be dumb bit buckets. Persistent objects should be true objects — they should contain behavior, as well as state, and they should encapsulate their state appropriately. Do not automatically use JavaBean accessor methods, encouraging callers to view persistent objects as pure storage. Likewise, avoid the temptation (as in traditional J2EE architectures using stateless session and entity beans) to move code for navigation of persistent object graphs into the business service layer, where it is more verbose and represents a loss of encapsulation.

Important 

Persistent domain models often represent the core intellectual property of an application, and the most valuable product of business analysis. To preserve this investment, they should ideally be independent of the means used to persist them.

Spring allows the application of Dependency Injection to persistent objects, using classes such as DependencyInjectionInterceptorFactoryBean, which enables Hibernate objects to be automatically wired with dependencies from a Spring IoC container. This makes it easier to support cases when domain objects might need, for example, to use a DAO interface. It allows this to be done simply by expressing a dependency via a setter method, rather than relying on explicit "pull" configuration calls to Spring or implementing persistence framework–specific lifecycle methods. (Another, more general, approach to this end is to use a class-weaving AOP solution such as AspectJ.) However, we advise careful consideration before allowing domain objects to access the service layer. Experience shows that it is not usually necessary in typical applications, and it may represent a blurring of the clean architectural layering we recommend.

Persistence Technology

Domain objects are typically persisted with an O/R mapping product such as Hibernate or a JDO implementation.

In certain cases, full-blown O/R mapping may be inappropriate. In this case, the DAO interfaces remain appropriate, but the implementation is likely to use JDBC — through Spring's JDBC abstraction layer, or through iBATIS SQL Maps.

In some applications — and some use cases in nearly any complex application — Spring's JDBC abstraction may be used to perform SQL-based persistence.

Business Service Objects

Depending on your chosen architecture, much of your business logic may reside in persistent domain objects.

However, there is nearly always an important role for a service layer. This is analogous to the layer of stateless session beans in traditional J2EE architectures. However, in a Spring-based application, it will consist of POJOs with few dependencies on Spring. The Service Layer provides functionality such as:

  • Business logic that is use case–specific: While it is often appropriate for domain objects to contain business logic applicable to many use cases, specific use cases are often realized in the business services layer.

  • Clearly defined entry points for business operations: The business service objects provide the interfaces used by the presentation layer.

  • Transaction management: In general, although business logic can be moved into persistent domain objects, transaction management should not be.

  • Enforcement of security constraints: Again, this is usually best done at the entry level to the middle tier, rather than in domain objects.

As with the DAO interface layer, the business service layer should expose interfaces, not classes.

Important 

The service layer also represents a valuable investment that — with good analysis — should have a long lifetime. Thus it should also be as independent as possible of the technologies that enable it to function as part of a working application. Spring makes an important contribution here through its non-invasive programming model.

Coupling between architectural layers should be in the form of interfaces, to promote loose coupling.

Presentation

In the recommended architecture using Spring, the presentation tier rests on a well-defined service layer.

This means that the presentation layer will be thin; it will not contain business logic, but merely presentation specifics, such as code to handle web interactions.

It also means that there can be a choice of presentation tiers — or more than one presentation layer — in an application, without impacting lower architectural layers.

Important 

Lower architectural layers should have no knowledge of presentation tier concerns.

Web Tier

In a Spring application, a web tier will use a web application framework, whether Spring's own MVC framework, or an alternative framework such as Struts, WebWork, Tapestry, or JSF.

The web tier will be responsible for dealing with user interactions, and obtaining data that can be displayed in the required format.

The web tier will normally consist of three kinds of objects:

  • Controller: Controller objects, like Spring MVC Controllers and Struts Actions, are responsible for processing user input as presented in HTTP requests, invoking the necessary business service layer functionality, and returning the required model for display.

  • Model: Objects containing data resulting from the execution of business logic and which must be displayed in the response.

  • View: Objects responsible for rendering the model to the response. The mechanism required will differ between different view technologies such as JSP, Velocity templates, or conceptually different approaches such as PDF or Excel spreadsheet generation. Views are not responsible for updating data or even obtaining data; they merely serve to display Model data that has been provided by the relevant Controller.

This triad is often referred to as an MVC (Model View Controller) architectural pattern, although such "web MVC" is not the same as the "classic" MVC pattern used in thick client frameworks such as Swing.

Spring's own MVC framework provides a particularly clean implementation of these three elements — the base interfaces have the names Controller, Model, and View. In particular, Spring MVC ensures that not only is the web tier distinct from the business services layer, but web views are completely decoupled from controllers and models. Thus a different type of view can be added without changing controller or model code.

Remote Access Facade

Spring reflects the philosophy that remote access — for example, supporting remote clients over RMI or remote clients over web services — should be viewed as an alternative presentation layer on well- defined middle tier service interfaces.

Important 

Unlike in traditional J2EE practice, remoting concerns should not cascade throughout an application in the form of Transfer Objects and other baggage.

Applications should be internally Object Oriented. As remoting tends to be destructive to true Object Orientation, it should be treated as one view of an application.

Spring provides a variety of remoting choices, based on exposing POJOs. This is less invasive than traditional J2EE EJB remoting, but it's important to remember that there are inevitable constraints around remoting, which no technology can wholly conceal. There is no such thing as a distributed object. Remoting introduces a range of concerns: not merely the need for serializability, but the depth to which object graphs should be traversed before disconnection, constraints on method granularity ("chatty" calling is ruled out for efficiency reasons), and many other issues.

If you wish to use a traditional EJB-based remoting architecture, you can use one or more Spring contexts inside the EJB container. In such an architecture, EJBs become a facade layer. (They may also be used for transaction management, although Spring's own transaction management is more flexible, and a better choice in Spring-based applications, even when using JTA.)

In such an architecture, we recommend that Transfer Objects and the other paraphernalia of remoting are added on top of the basic architecture, rather than used throughout it.

Spring RCP

Another important presentational choice is the Spring Rich Client Project (Spring RCP). This is a framework built around the Spring IoC container that facilitates the building of Swing applications. The use of Spring on the client side is especially compelling when it is necessary to access enterprise services, which are typically remote, as Spring's client-side, as well as server-side, remoting features may be used.



Professional Java Development with the Spring Framework
Professional Java Development with the Spring Framework
ISBN: 0764574833
EAN: 2147483647
Year: 2003
Pages: 188

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net