Spring is perhaps the only successful software project to have evolved from a book: Expert One-on-One J2EE Design and Development, by Rod Johnson (Wiley, 2002). This unusual heritage has proved beneficial, providing Spring with a consistent vision from its outset. From the outset, the Spring team agreed on coding and design conventions, and the overall architecture approach that Spring should enable.
Spring initially grew out of Rod Johnson's experience as a consultant on various large Java/J2EE applications from 1997 through 2002. Like most experienced consultants, Rod had written a number of frameworks for various clients. The last, for a prominent global media group, began as a web MVC framework (well before Struts was available), but expanded to include what would now be called a Dependency Injection container (although the name did not exist until late 2003) and data access services.
Thus Expert One-on-One J2EE Design and Development included not only a discussion of the problems Rod had encountered doing extensive J2EE development, but 30,000 lines of code, in the form of the "Interface21 framework" demonstrating a practical approach to solving many of them.
The reaction to this code from readers was extremely positive, many finding that it solved problems that they'd seen over and over in their own J2EE experience. Over the next few months, numerous readers sought clarification of the terms of the license so that they could use the code in projects and — far more important — volunteered ideas and practical help to take the framework to the next level.
The most important contribution was made by Juergen Hoeller, who has been co-lead with Rod since the open source framework was founded in February 2003. Juergen immediately began to make a huge contribution to implementation and design. Other developers including co-authors Thomas Risberg, Colin Sampaleanu, and Alef Arendsen also joined early and began to make large contributions in specific areas.
Interestingly, the ideas that Spring is commonly identified with — most notably, Dependency Injection — were also developed independently by other projects. Although it was publicly announced before Spring went public, the PicoContainer project actually began several months after the Spring project.
The ATG Dynamo application server included a Dependency Injection capability in its proprietary functionality, although none of the Spring team was aware of this until Spring was already widely adopted. Proof that an idea so simple, yet powerful, cannot be invented — merely discovered.
The authors of this book include most of the core developers of Spring. Rod and Juergen remain the architects and chief developers of Spring.
The Spring community has also made a huge contribution to the evolution of Spring, through reporting problems based on experience in a wide range of environments, and suggesting many improvements and enhancements. This is a key element in the value proposition of open source infrastructure — indeed, any off-the-shelf infrastructure, as opposed to in-house frameworks. Not only can a large community of talented individuals contribute ideas to the framework itself, but a large body of understanding is available to organizations building applications using Spring.
From its outset, the Spring project has been based around respecting and listening to Spring users. Of course, as any project grows in size, it becomes impossible for any individual to participate in all discussions — even to listen attentively to the details of every discussion. But the Spring developers as a group have been attentive and responsive, and this has helped to build a flourishing community.
Spring is licensed under the Apache 2.0 license — a widely used open source license that is not restrictive.
In August 2004, Rod, Juergen, Colin, and other core Spring developers (including Spring RCP lead, Keith Donald) founded Interface21, a company devoted to Spring consulting, training, and support. This helps to secure the future of Spring, by placing a viable economic model behind it. A sophisticated and wide- ranging framework such as Spring represents a huge amount of effort; it's impossible to continue that effort without a viable economic model. Spring framework itself will always remain open source and free to anybody who wishes to use it. However, the existence of a commercial entity also provides a degree of confidence to more conservative organizations, with the availability of professional services to support the development of Spring-based applications.
Even before the release of Spring 1.0 final in March 2004, Spring had been widely adopted. Today, Spring is one of the most widely used and discussed products in J2EE development, and Spring skills are widely available and sought after on the job market.
Let's now examine the functionality that Spring offers in more detail. It is divided into a number of separate modules.
There are two main categories of functionality in Spring:
An IoC container and AOP framework, which handle configuration and application of services to objects.
A set of services that can be applied to application objects. These services can be used as a class library, even in a different runtime container.
Each of the modules discussed here fits into one or both of these categories.
Spring is a layered framework with the following core modules:
IoC container: The core of Spring is the IoC container. This configures objects by Dependency Injection, but also supports a variety of optional callbacks for application objects that have more complex requirements of their environment. 33
Proxy-based AOP framework: Spring's AOP framework is the other essential in delivering a non-invasive framework that can manage POJOs. Spring AOP can be used programmatically, or integrated with the IoC container, in which case any object managed by a Spring IoC container can be "advised" transparently.
Data access abstraction: This includes:
The DAO exception hierarchy and consistent architectural approach discussed earlier in this chapter.
Template and other integration classes for Hibernate, JDO, TopLink, iBATIS, and other data access APIs.
Spring's own JDBC abstraction framework. While in general Spring's approach to persistence is consistent integration, Spring does provide one persistence API of its own: its JDBC framework. This is an abstraction layer over JDBC that simplifies error handling, improves code portability, and eliminates the potential for many common errors when using JDBC, such as failure to close connections and other valuable resources in the event of errors. Spring's JDBC abstraction is suitable when you want SQL-based persistence, and not O/R mapping: for example, when you have a legacy database that doesn't lend itself to O/R mapping, or you need to make extensive use of stored procedures or BLOB types. Spring's JDBC framework is also a good choice if the persistence needs are limited and you don't want to introduce the learning curve/maintenance cost of an additional persistence framework such as JDO or Hibernate.
Transaction abstraction: Spring provides a transaction abstraction that can run over a variety of underlying transaction APIs, including JTA, JDBC, Hibernate, and JDO transactions. Naturally, JTA is the only option for working with multiple transactional resources, as Spring does not provide its own distributed transaction manager. However, many applications work with a single database, and do not require distributed transactions for any other reason (such as working with JMS). However, Spring's transaction abstraction provides a consistent programming model in any environment, from high-end J2EE application servers down to simple web containers and standalone clients: a unique value proposition that does away with the traditional need to choose between "global" and "local" transaction management and commit to one or another programming model early in each J2EE project. Spring provides programmatic declarative management that is much more usable than JTA, which is a fairly cumbersome API, not ideally suited for use by application developers. But most users prefer Spring's sophisticated declarative transaction management, which can provide transaction management for any POJO. Spring transaction management is integrated with all of Spring's supported data access integrations.
Simplification for working with JNDI, EJB, and other complex J2EE APIs and services: If you're an experienced J2EE developer, you will have written many JNDI lookups. You may have chosen to move the lookup code to a helper class, but you can't completely conceal the complexity, or hide the implications for testing. If you've worked with EJB, you've needed to write code to look the EJB home up in JNDI before calling the create() method to obtain an EJB reference you can use to do work. Chances are, you've done essentially the same thing, over and over, and worked on applications where many developers have done essentially the same thing over and over, but in various different ways. These are routine tasks that are much better done by a framework. Spring's support for JNDI and EJB can eliminate the need to write boilerplate code for JNDI lookups and EJB access or implementation. By eliminating JNDI and EJB API dependencies in application code, it also increases the potential for reuse. For example, you don't need to write code that depends on an EJB home interface or handles EJB exceptions; you merely need to express a dependency on the relevant EJB's Business Methods Interface, which is a plain Java interface. Spring can do the necessary JNDI lookup and create an AOP proxy for the EJB that hides the need to work with the EJB APIs. Your code is no longer dependent on EJB — you could choose to implement the Business Methods Interface without using EJB — and another bit of tedious boilerplate is gone.
MVC web framework: Spring's own request-driven MVC framework. This is closely integrated with Spring's middle-tier functionality, with all controllers being configured by Dependency Injection, providing the ability to access middle-tier functionality from the web tier without any code. Spring MVC is similar in how it approaches controller lifecycle to Struts, but provides some key benefits over struts, such as:
Better support for view technologies other than JSP, such as Velocity and PDF generation libraries
Interceptors, in addition to "actions" or "controllers"
Ability to use domain objects to back forms, rather than special objects such as Struts ActionForm subclasses
Interface-based design, making the framework highly customizable, and avoiding the need to subclass framework classes, which is a convenience rather than a necessity
Integration with numerous third-party products: This fits into Spring's role as architectural glue. As the Spring IoC container is extensible, it's also easy to "alias" additional services into Spring IoC. The JndiObjectFactoryBean, which looks up a named object in JNDI, is a good example.
Remoting: Spring provides lightweight remoting support over a variety of protocols, including web services, RMI, RMI over HTTP, IIOP, and Caucho's Hessian and Burlap protocols. Remoting is available for POJOs, in keeping with Spring's emphasis on providing a rich environment for POJOs.
Simplification for working with EJBs: This consists of:
Support for implementing EJBs: EJB 2.1 and earlier have no built-in configuration management. EJB 3.0 looks set to offer a simplistic Dependency Injection capability. In either case, there is a compelling value proposition in using a lightweight container behind an EJB facade. Spring provides support for implementing EJBs that serve as a facade in front of POJOs managed by a Spring application context.
Support for accessing EJBs, via the "codeless proxying" described earlier.
Message publication using JMS: Spring's callback template approach is ideally suited to minimizing the complexity of application code required to publish JMS messages.
JMX support: Spring 1.2 provides a powerful JMX layer that can publish any Spring-managed object to JMX, enabling monitoring and management with standard tools.
When you use Spring's AOP framework, a layer of dynamic capabilities is available over the Spring IoC container in Spring 1.3:
Support for scripting languages, with full support both ways for Dependency Injection. This means that any application object can be written in any supported scripting language, depending on other objects written in Java, or vice-versa.
Support for objects backed by a database.
Quite a list! This broad scope sometimes leads people to the misconception that Spring is a big fat blob, which aims to do everything from scratch. It's important to emphasize the following points:
Spring's modular architecture means that you can use any part of Spring in isolation. For example, if you want to use just the IoC container to simplify your configuration management, you can do so, without the need for any other part of Spring. If you want to use Spring AOP, you can do so without the IoC container. You might choose to use Spring's transaction interceptor in another AOP framework, or the Spring JDBC framework as a class library.
Yet there is a consistency in the design of the different Spring modules that is very helpful if you choose to use more of the Spring stack, as you can leverage the same concepts in different areas, making your application more internally consistent and making the whole framework easier to learn than you might expect, given its scope.
Spring is substantially about integrating best-of-breed solutions.
Although the Spring download is quite large, this results mainly from its integration with other products. To run the core IoC container, you need only the Jakarta Commons Logging JAR in addition to the Spring binary. Some advanced features of both IoC container and AOP framework require CGLIB, which is also used by Hibernate and many other products. Beyond that, Spring's dependencies depend on what third-party product you integrate it with. For example, if you use Spring and Hibernate, you need a number of JARs that are required by Hibernate, besides Hibernate's own JAR.
Spring provides a number of JARs itself, offering separate services:
spring.jar (1.4MB): Contains all core Spring classes, including all classes from the following JARs except spring-mock.jar.
spring-core.jar (265K): The core IoC container and utility classes used elsewhere in the framework.
spring-context.jar (276K): More advanced IoC features, JNDI and EJB support, validation, scheduling, and remoting support.
spring-aop.jar (144K): Spring's AOP framework.
spring-dao.jar (241K): Spring's data access exception hierarchy, JDBC abstraction, and transaction abstraction, including JTA support.
spring-orm.jar (190K): Integration with Hibernate, JDO, iBATIS, and Apache OJB.
spring-web.jar (114K): ApplicationContext implementations for use in web applications (with any web application framework), servlet filters, integration with Struts and Tiles, web data binding utilities, and multipart support.
spring-webmvc.jar (190K): Spring's own Web MVC framework.
spring-mock.jar (40K): Mock object implementations and superclasses for JUnit testing objects in a Spring container. Includes test superclasses that can begin and roll back a transaction around each test. These superclasses enable JUnit test cases themselves to be configured by Dependency Injection. (Objects to be tested are injected.)
Most users find that using spring.jar is the simplest choice. However, as the file sizes indicate, the core IoC container comes in at little over 200K.
Spring requires J2SE 1.3 or above. Spring uses J2SE 1.4 optimizations where this will produce significant benefit, but falls back to using J2SE 1.3 APIs if necessary. For example, there are a number of optimizations available to the AOP framework under J2SE 1.4, such as the use of the new IdentityHashMap and StackTraceElement, which enable Spring's AOP framework to run faster on J2SE 1.4 and above. But it still retains full functionality on J2SE 1.3.
Certain additional features are supported only in Java 5.0. For example, Spring supports Java 5.0 annotations to drive declarative transaction management. However, the implementation of the core framework will remain J2SE 1.4 compatible for the foreseeable future. Our experience is that large enterprise users, in particular, often use older versions of application servers, and tend to be slow in upgrading. (At the time of writing, one of the major users of Spring in London, a global investment bank, is still using J2SE1.3, with an old version of WebSphere.)
The Spring core does not depend on J2EE APIs. The IoC container and AOP frameworks can be used outside the J2EE environment. Even the transaction support can be used with a full J2EE environment (with JTA).