Quantcast
Channel: JAW Speak
Viewing all articles
Browse latest Browse all 10

Spring Bean Autowiring into Handler/Controller Method Arguments

$
0
0

Reading time: 2 – 4 minutes

We request scope controllers in our Spring MVC web application, and then spring injects in collaborators. Each request builds up an object graph of mostly request scoped components, they service the request, and are then garbage collected. Examples of collaborators are Services, request-scoped objects like User, or objects from session. Declare these injectables as dependencies of your controller, and the IoC framework will resolve those instances for you. Using Spring’s FactoryBean, you can have custom logic around retrieving from a DB or service call. (Also, if you do request scoping for everything you will probably want to make your FactoryBeans caching, or create a custom scope, so Spring doesn’t recreate each FactoryBean, and make a remote call possibly, on every object injection.)

Instantiate a graph of request-scoped objects per request. Is that crazy? Not really, because garbage collection and object instantiation are very fast on modern JVM’s. I argue that it it helps you have cleaner and more maintainable code. Designs have better object orientation, tests don’t require as many mocks, and it’s easier to obey the single responsibility principle.

None of this is new, though. Here’s where it gets interesting for us. We have @RequestMapping methods on a controller, but only one of them needs the injected collaborator. If it is slow to retrieve the collaborator (such as a CustomerPreferences we get from a remote call), we don’t want to call it every time. Sometimes this means you need two controllers, other times you want to let any spring bean be injected into a handler method.

We extended Spring to inject any spring bean into a controller/handler’s @RequestMapping or @ModelAttribute annotated methods. You benefit with only injecting the bean into the handler method that needs it, possibly preventing remote calls to lookup said dependency if it were a field on a controller with multiple @RequestMapping’s.

Here’s a sample controller’s handler method. Before:

	@RequestMapping(value = Paths.ACCOUNT, method = GET)
	public String showAccount(Map model) {
	      model.put("prefs", customerService.getCustomerPrefs(session.getCustomerId()));
	      return "account";
	}

There is an extension point WebAttributeResolver for you to add your own logic to resolve method parameters (such as autowire them as spring resolvable beans). After:

	@RequestMapping(value = Paths.ACCOUNT, method = GET)
	public String showAccount(Map model,
	          @AutowiredHandler CustomerPreferences customerPreferences) {
	      // the CustomerPreferences has a CustomerPreferencesFactoryBean which
	      // knows how to make a remote service call and retrieve the prefs.
	      model.put("prefs", customerPreferences)); // easier to test
	      return "account";
	}

This lets you inject any spring bean into fields/methods annotated with @ModelAttribute or @RequestMapping.

Another very helpful way to do this is to automatically inject User or other request-specific objects.

References for further discussion/examples on the topic:
http://karthikg.wordpress.com/2009/10/12/athandlerinterceptor-for-spring-mvc/
http://karthikg.wordpress.com/2010/02/03/taking-spring-mvc-controller-method-injection-a-step-further/


Viewing all articles
Browse latest Browse all 10

Trending Articles