Inversion of control simplifies configuration
I started out on my quest to answer all the questions I had about the Spring Framework by turning to Jeff Genender, Geronimo committer and all-around talented guy, and asking him, for those of us not familiar with it, just what is Spring, anyway?
A little research had told me that Spring is a Web application API and that it includes an implementation of the Model-View-Controller (MVC) model for those who are unhappy with Struts. But what makes it such a big deal? What's the killer feature that seems to provide critical mass for this framework?
"Spring is an IoC container," Jeff explained. "That stands for Inversion of Control, which enables you to inject dependencies by declaring them in an XML file."
IoC was a new term for me, so Jeff explained that when you're creating an application, you typically have one object that relies on another object. For example, you might have a business object that represents, say, a sandwich maker. That sandwich maker refers to a second object, the sandwich filler. So you might have code like this (see Listing 1).
Listing 1. A sample class
package com sandwiches;
public class SandwichMaker implements FoodMaker {
private SandwichFiller filler;
private String currentSandwich;
public void setSandwichFiller(SandwichFiller filler) {
this.filler = filler;
}
public void setNameOfSandwich(string currentSandwich) {
this.currentSandwich = currentSandwich;
}
public void makeSandwiches() {
//make sandwiches using the SandwichFiller
}
}
|
Now of course, the actual SandwichFiller is going to depend on what kind of sandwiches you want to make. So you might have a different implementation of the SandwichFiller class for a bagel shop than you would for a submarine shop. When you instantiate the SandwichMaker class, you can, of course, provide the appropriate implementation of SandwichFiller by calling the setSandwichFiller() method. But then you would need to change the code to install the SandwichMaker in a new location. Spring enables you to create an application context that includes definitions for these dependencies. (This is why this is sometimes called dependency injection.)
The file might look like Listing 2.
Listing 2. The ApplicationContext.xml file
<beans>
<bean id="bagel" class="com.sandwiches.BagelShop">
<property name="breadPreference" value="bagel" />
<property name="diameter" value="5" />
</bean>
<bean id="ccandjFiller" class="com.sandwiches.CreamCheeseAndJellyFiller">
<property name="sandwichType" ref="bagel" />
<property name="creamCheesePortion" value="60" />
<property name="jellyPortion" value="40" />
<property name="jellyFlavor" value="grape" />
</bean>
<bean id="sandwichMaker" class="com.sandwich.SandwichMaker">
<property name="sandwichFiller" ref="ccandjFiller" />
<property name="nameOfSandwich" value="Cream Cheese and Jelly" />
</bean>
</beans>
|
Okay, let's look at this more closely, starting at the bottom. We've told the environment that when we instantiate the class com.sandwich.SandwichMaker, the property sandwichFiller should be populated by the bean identified as ccandjFiller. That bean is a com.sandwiches.CreamCheesAndJellyFiller, which has its own properties. It has a sandwichType of bagel, which sets the breadPreference to bagel (rather than rye or bialy), and it's five inches wide. Also, we want just a little more cream cheese than grape jelly.
Now, that's an awful lot of customization; if you wanted to program that into the application, it would mean a lot of recompiling when things changed, or a lot of work building in the option to make all those choices. Spring makes it easy to make changes by just altering an XML file. I've chosen a somewhat lighthearted example here, but imagine that you're configuring data sources and all of a sudden this IoC becomes invaluable.
Speaking of data sources, Jeff explained that this is another area in which "Spring has an excellent API that extends many J2EE (and non-J2EE) components, making the developer's life a lot easier.
"Creating Data Access Objects in Spring is relatively simple," he explained. "You extend a couple of Spring classes with your JDBC (or other framework like Hibernate), implement your DAO, then make the declaration in the applicationContext.xml file. You can then inject these DAOs declaratively into your business objects just by making a setter for the DAO and declaring the business object in the Spring XML file."
That much I had learned in our discussion on IoC. But there's more: "By doing this, you do away with having to trap for SQLExceptions and make testing [of a database] as simple as swapping your declarations."
I understood this last part; the database is a property you can easily set in the applicationContext.xml file. But how does it keep you from having to trap for SQLExceptions?
"Spring hides the JDBC SQL issues by converting the SQLExceptions, and so on, to unchecked exceptions. They then also clean up the errors, which makes it so it is very clear what the problem is. It's a much better approach to doing database exceptions."
Basically, when you create a JDBC application, and something goes wrong, you get a SQLException. Unfortunately, that SQLException rarely contains all the information you need to actually find out what went wrong, because the real information is encoded as vendor-specific error codes that you have to track down. And of course, since part of the point here is that you can easily change data sources, coding the intelligence into the application isn't an option. However, by wrapping your database interactions in Spring classes, such as JdbcTemplate, you make sure that any errors are expressed as a DataAccessException, or more importantly, as one of the DataAccessException's dozen or so subclasses, which include DataAccessResourceFailureException, DataIntegrityViolationException, and OptimisticLockingFailureException. This way you can code your application much more intelligently.
Hidden classes prevent clashes
Well, that was a lot of information about Spring, but what about Geronimo? Did the team have to do any special work to integrate it into the application server?
"I believe Bruce Snyder and Aaron Mulder wrote a Spring plug-in for the Apachecon 2006 presentation they gave on plug-ins, but outside of that, Spring is really an API, so with Spring, you can place it into our repository, and it's available to all to use."
In other words, they didn't have to do anything special; Spring is just available as long as it's in the repository.
But that's not the end of the story. Jeff continued, "One of the biggest complaints people have on other application servers is that you need to place Spring in the server's classpath, and when you also include it in your Web application" -- as you must do if your application uses a different version of Spring than the server has installed -- "you get a clash of which Spring is being used. It's part of the parent-child, child-parent classloading dichotomy of J2EE apps."
The problem is that in some situations, Java™ 2 Platform, Enterprise Edition (J2EE) or Java Platform, Enterprise Edition (Java EE) starts at the most specific level looking for a class to instantiate (in which case it uses the classes that are part of the application), and in others it uses the most general (in which case it uses the classes that are part of the server). The result is that you might create a resource in the context of the application, but when you try to access it, the server is looking in the context of the application server.
"This will make your apps not find [their] Hibernate resources, etcetera, because they get created in one Spring container and accessed in another."
Originally, the Geronimo developers solved this problem by auto-hiding certain common classes, such as Spring and Apache Commons Logging, a frequent cause of this trouble. But things came to a head with Liferay, an open source JSR 168-compliant portal (see Resources for a link). Liferay uses Spring and includes a version of Spring in the .ear file for all of the sub-applications deployed in it. "The reason I mention them," Jeff told me, "is that our hidden classloading architecture caused a problem early on because we were auto-hiding Spring so their Web apps couldn't see the EAR-level version of Spring."
Finally, the Geronimo developers hit on a solution. "But we have one better thing than most other app servers. Many people run into issues regarding commons logging. When they run in a container that uses commons logging, like JBoss, Tomcat, etcetera, and they include the commons-logging JAR [file] in their app, they run into nasty exceptions." These are the same problems encountered by Spring applications before the initial changes. "It really is a matter of classloaders clashing. We had a few open issues saying Web apps didn't work, but they did; they just needed to remove commons logging, like needed to be done for Tomcat and JBoss, etcetera. So we had a lot of discussions and started to hardcode blocking classes like commons logging. Discussion ensued, and we figured a declarative approach was much better. And thus the hidden classes declaration was born. We have the ability to declare hidden classes in our plan files, which you use to deploy your apps."
"It works great," he continued. "So we don't have the problem many other containers have. You control the classloader for parent-child child-parent delegation. So with Geronimo you can declare that your app only uses the Spring that is included in your app, ignores the server version, or vice versa. The other positive about that is you can use multiple versions of Spring. So if the server is using 2.0 and your legacy app used 1.x, you can ensure no clashing will occur, and your app uses the proper version."
Adding more to Apache Geronimo for Spring
While Spring may have been what pushed the team to make these changes, they're useful for any class for which this might be a problem. But that doesn't mean that Spring-specific work won't one day end up in Geronimo.
"Now I was just talking with Bruce Snyder," Jeff told me after wrapping up a phone call while I grabbed a quick bite. "We were talking about building or extending a plug-in to allow you to place Spring ApplicationContexts in the JNDI, so you could have server-wide access to Spring-based objects. I have written this for a client and think it should be a core function for an app server. It's a matter of getting time to do it," he said, smiling.
"At some point we will do it," he said. "It's nice to offer server-based Spring objects to applications. You could store specific objects or references to objects for Spring that you want your applications to have access to. For example, if you are using Quartz, and you want a reference to the container, and you created objects via Spring, you may need access to the ApplicationContext that has a reference to that object, thus it needs to be widely available. Storing it in the JNDI will give your applications access to other ApplicationContexts that were started in another context. This would be huge for Service-Oriented Architecture- and enterprise service bus-based applications, which is where I developed this before. I guess in a nutshell, to put it more directly, it's good for applications that aren't connected but need access to common resources. That's the best way to put it. SOA apps need this functionality."
We talked a bit longer about all the hard work the Geronimo committers and community were doing, and I took my leave, finally understanding what all the fuss is about. Spring seems to be a pretty handy framework to have around. It's obvious how IoC and dependency injection can make my life a whole lot easier when applications require any sort of configuration change, and I've wasted way too many hours of my life trying to decipher SQLExceptions not to appreciate Spring's approach to data access. What's more, I learned something about classloaders and why I sometimes get errors that seem to defy any sort of problem solving, so I definitely appreciate Geronimo's hidden class declaration.
Now if somebody could just explain the big deal about JavaServer Faces (JSF) technology.
Learn
-
Read Arun Chaatpar's six-part series on using Geronimo and Spring, starting here with "Apache Geronimo and the Spring Framework, Part 1: Development methodology" (developerWorks, September 2006).
-
Get a nice introduction to Spring from its founder, Rod Johnson.
-
Learn about how Spring handles data access in Chapter 12. Object Relational Mapping (ORM) data access from the official Spring Framework documentation.
-
Learn more about the classloader issues discussed in this article in "Taxonomy of class loader problems encountered when using Jakarta Commons Logging" (February 2005).
-
Check out the open source Liferay portal server.
-
Get involved in the Apache Geronimo project.
-
Join the mailing list for Geronimo at apache.org.
-
Get guidance for software developers, both inside and outside the Apache projects, to understand what to do to apply the Apache License, Version 2.0.
- Check out the developerWorks Apache Geronimo project area for articles, tutorials, and other resources to help you get started developing with Geronimo today.
- Find helpful resources for beginners and experienced users at the Get started now with Apache Geronimo section of developerWorks.
- Check out the IBM® Support for Apache Geronimo offering, which lets you develop Geronimo applications backed by world-class IBM support.
- 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.
- Stay current with developerWorks technical events and webcasts.
- Browse all the Apache articles and free Apache tutorials available in the developerWorks Open source zone.
- Browse for books on these and other technical topics at the Safari bookstore.
- Get an RSS feed for this series. (Find out more about RSS.)
Get products and technologies
-
Get a menu of Apache Geronimo downloads, including Little G.
- Download the latest version of Apache Geronimo.
- Download your free copy of IBM WebSphere® Application Server Community Edition -- a lightweight J2EE application server built on Apache Geronimo open source technology that is designed to help you accelerate your development and deployment efforts.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
- Participate in the discussion forum.
- Stay up to date on Geronimo developments at the Apache Geronimo blog.
- Get involved in the developerWorks community by participating in developerWorks blogs.
Nicholas Chase has been involved in Web-site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. He has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the chief technology officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).





