Spring prototype scoped beans and dependency injection

toy car Spring prototype scoped beans and dependency injection
Within the typical Spring container most of the beans with dependency on other beans end up being stateless singleton beans. However every once in a while you want a stateful prototype beans with dependencies. A common example of this scenario comes to mind when implementing the BusinessDelegate pattern within a Spring managed application.

In this example I have a SearchBusinessDelegate which depends on MyService to execute the search.



MyService‘s interface:

public interface MyService {
	List<Long> executeSerch(final int maxResults, final SearchCriteria criteria);
}

and here is SearchBusinessDelegate‘s implementation:

public class SearchBusinessDelegate {

	private final MyService myService;

	private SearchCriteria statefulCriteria;
	private int maxResults;

	public SearchBusinessDelegate(final MyService myService) {
		this.myService = myService;
	}

	public void initCriteria(final SearchCriteria searchCriteria, final int maxResults) {
		this.statefulCriteria = searchCriteria;
		this.maxResults = maxResults;
	}

	public List<Long> executeSearch() {
		Assert.isTrue(maxResults > 0, "maxResult cannot be less than 1");
		Assert.notNull(statefulCriteria, "search criteria cannot be null");
		return myService.executeSerch(maxResults, statefulCriteria);
	}
}

Notice the delegate’s mix of load time dependencies and run time parameters. IMO you should be extremely cautious about using these kind of stateful delegates, one noticeable drawback of this implementation is the need to assert that initCriteria was invoked prior to invoking executeSearch, which is a foxhole. For the sake of implementing the pattern correctly this is now kept as is.

The traditional way of doing this is to implement a BusinessDelegateFactory which gets injected the BusinessDelegate‘s dependencies and does the dependency injection on the business delegate upon creation. For example:

public class SearchBusinessDelegateFactory {
	private final MyService myService;

	public SearchBusinessDelegateFactory(final MyService myService) {
		this.myService = myService;
	}

	public SearchBusinessDelegate create(final SearchCriteria searchCriteria, final int maxResults) {
		final SearchBusinessDelegate delegate = new SearchBusinessDelegate(myService);
		delegate.initCriteria(searchCriteria, maxResults);
		return delegate;
	}
}

And the Spring configuration would be:

<bean id="myService" class="org.echotech.service.MyServiceImpl" />

<bean id="searchBusinessDelegateFactory" class="org.echotech.service.SearchBusinessDelegateFactory">
	<constructor-arg ref="myService" />
</bean>

Using this factory however causes us to lose IoC principle en-route. We are creating the delegate in code which kind of defeats the purpose (for example, think about how you’d wrap the SearchBusinessDelegate‘s with AOP interception this way), bummer. We could have our factory implement the ApplicationContextAware and retrieve the prototype instance from the context each time. But this factory code, is it really necessary? isn’t that the purpose of using Spring in the first place?

The answer is yes, we can take advantage of Spring’s ObjectFactory implementations, namely ObjectFactoryCreatingFactoryBean.

First we define the factory in Spring:

<bean id="myService" class="org.echotech.service.MyServiceImpl" />

<bean id="searchBusinessDelegate" class="org.echotech.service.SearchBusinessDelegate"
	scope="prototype">
	<constructor-arg ref="myService" />
</bean>

<bean id="searchBusinessDelegateFactory"
	class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
	<property name="targetBeanName">
		<idref local="searchBusinessDelegate" />
	</property>
</bean>

Now we can wire the factory in our client (in this case, a controller) which ensures a fresh instance of the delegate (prototype scope in Spring) is used for every invocation of executeSomething method:

@Controller
public class MyController {

	private final ObjectFactory<SearchBusinessDelegate> delegateFactory;

	public MyController(final ObjectFactory<SearchBusinessDelegate> delegateFactory) {
		this.delegateFactory = delegateFactory;
	}

	@RequestMapping(method = RequestMethod.GET)
	public List<Long> executeSomething(@RequestParam(value = "keyword") final String keyword) {
		final SearchBusinessDelegate delegate = delegateFactory.getObject();
		delegate.initCriteria(new SearchCriteria(keyword, true), 100);
		return delegate.executeSearch();
	}
}

This way we can get a prototype instance of our delegate for each invocation while taking advantage of Spring dependency injection and other Spring features (e.g., AOP, post processing, etc.) for our prototype.


1 Trackbacks

You can leave a trackback using this URL: http://techo-ecco.com/blog/spring-prototype-scoped-beans-and-dependency-injection/trackback/

  1. [...] a previous post I showed how to use Spring prototype scoped beans with dependency injection. In this post I’d [...]

One Comment

  1. here is a best differentiation of the singleton vs. the prototype scopes of Spring Framework

    http://www.adobocode.com/spring/springs-scopes-singleton-vs-prototype

    Posted November 12, 2010 at 12:30 AM | Permalink | Reply

Post a Comment

Your email is never shared. Required fields are marked *

*
*