Simple URL mapping and factory beans in Spring
As explained in Basic Spring Web MVC Example and Basic Web MVC Example - In Pictures, Spring’s dispatcher servlet uses a URL mapper to map requests that come into the dispatcher servlet to appropriate handlers. Indeed, the example application used a ’simple URL mapper’ that mapped all requests to the same handler. Despite its name, this is one of the better handlers, so in this entry we will explore how to configure the URL handler. Along the way we’ll learn about factory beans, and the PropertiesFactoryBean in particular.
Background
Our sample skeleton1 application had the following hander mapping:
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/*">dispatchController</prop>
</props>
</property>
</bean>
As explained in the blog entries above, this maps all incoming requests to the same handler, dispatchController. In fact, Spring’s handler infrastructure is pretty flexible, allowing you great control over what gets mapped where. Even when. Yes, when. You can, for example, define handler interceptors - perhaps you’ll only allow URL’s to go through to a particular handler when the user is authenticated for example, or if the moon is full. We’ll examine those in a later show. Now, however, let’s look at ways to configure the URL mapper.
How to do it
They easiest way to get started is to use the SimpleUrlHandlerMapping class and a property listing the mapping. As the name suggests, this handler lets you map simple URLs to handlers. In fact, the URLs aren’t that simple. They can be “Ant-style pattern matches” - for example /f* will match /foo and /flumoxed, /menu/* matches anything in the /menu/ directory (for example, /menu/foo but not /menu/foo/bar), and /menu/** matches any kind of URL that starts with /menu/, including /menu/foo/bar. Here’s a simple set of mappings:
<property name="mappings“>
<props>
<prop key=”/bar/*”>dispatchController</prop>
<prop key=”/fum/**”>someOtherDispatchController</prop>
</props>
</property>
As have probably figured out, the SimpleUrlHandlerMapping class has a setMappings(Properties p) method that allows you to configure it. It also has setUrlMap(Map urls) method, which allows for a more bean-like approach:
<property name="urlMap“> <map> <entry key=”/bar/*”><ref local=”dispatchController”/></entry> <entry key=”/fum/**”><ref local=”dispatchController2″/></entry> </map> </property>
Here we’re obviously referring to the dispatchController bean, which we will have defined in the context configuration file. It’s slightly more verbose than the previous listing, but some folk like this stronger notion of bean references.
One final approach is to place the mapping in an external file—we prefer this approach. For example, create a properties files mapping.properties and put it in /WEB-INF/. It can look like this:
/foo/*=dispatchController /bar/*=dispatchController2
Then, modify your dispatch-servlet.xml like this:
<bean id="mappedProperties”
class=”org.springframework.beans.factory.config.PropertiesFactoryBean”>
<property name=”location”>
<value>/WEB-INF/mapping.properties</value>
</property>
</bean>
<bean id=”urlMapping”
class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
<property name=”mappings”><ref local=”mappedProperties“/></property>
</bean>
That’s it. Note that the urlMapping bean now takes its mapping from a referenced property, mappedProperties, and this bean, instead of listing out each property individually, instead utilizes PropertiesFactoryBean to populate the properties from the referenced file.
Advanced
You may be scratching your head at this stage saying, “okay, I can see that it works, and I know how to use it, but how does it work?” How indeed. PropertiesFactoryBean does not implement the Properties interface, so how could this possibly substitute as something of type Properties?
It turns out that PropertiesFactoryBean is a Factory Bean - it is a bean that generates beans. In this case, its a bean that generates other beans of type Properties. Let’s see how it works by looking at its definition:
public class PropertiesFactoryBean extends PropertiesLoaderSupport
implements FactoryBean, InitializingBean {
…
Object getObject() { return this.singletonInstance; }
Class getObjectType() { return Properties.class; }
boolean isSingleton() { return true; }
…
}
I’ve highlighted the methods it has to implement because it’s a FactoryBean. isSingleton() provides us with a little control over object creation. When I generate a bean, should I make a new instance every time (prototype), or simply use one I created earlier (singleton). getObject() returns the actual object, in this case a Properties object that’s been populated from the file. getObjectType() returns the type of the object that we’re generating. So how does all this work?
It turns out that deep in the bowels of Spring’s IoC container, you have a getBean() method - which returns a bean instance given its name. [This is called when you have something like this for example: . This forces Spring’s container to go look for a bean called beanname, which eventually calls getBean().]
This eventually calls down into another method (getObjectForSharedInstance()) which retrieves the bean (say from the context of beans that you created), and examines it to see if its a factory instead of a normal bean. If it’s a ‘normal’ bean, it simply returns the instance. If it’s a factory bean, it instead asks the factory to generate an instance to return. See:
beanInstance = /* some instance from the list of beans we've configured */
if (beanInstance instanceof FactoryBean) {
// Return bean instance from factory.
FactoryBean factory = (FactoryBean) beanInstance;
beanInstance = factory.getObject();
}
return beanInstance;
As you can see, it’s pretty straightforward. If we are trying to grab an ordinary bean, we simply return the instance that we’ve found. If, however, it’s a factory bean, we ask the factory to generate the instance that we return. Voila!
This FactoryBean mojo is used all over Spring - for example, especially where Spring has to bridge to another technology. The code that does the bridging can be stuffed in a factory bean, and it in turn can generate beans of the required type when called to do so. We’ll encounter it many times in the future, so read this again if you didn’t get it all the first time!
Print This Post
on February 18th, 2006 at 2:41 pm
[…] MemeStorm » Simple URL mapping and factory beans in Spring (tags: spring java) […]
on October 5th, 2006 at 5:42 am
dispatchController
someOtherDispatchController
Not working I’m doing
doc
Error:
java.lang.IncompatibleClassChangeError
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.lookupHandler(AbstractUrlHandlerMapping.java:136)
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.getHandlerInternal(AbstractUrlHandlerMapping.java:117)
org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:95)
on November 22nd, 2007 at 11:45 am
[…] shown in Simple URL Mapping…, a URL Mapper has to map incoming URL requests to particular controllers. Typically we have to […]