JAW Speak

Jonathan Andrew Wolter

Archive for the ‘spring’ tag

Spring Slow Autowiring by Type getBeanNamesForType fix 10x Speed Boost >3600ms to <100ms

with 9 comments

Reading time: < 1 minute

We’re using Spring MVC, configured mostly by annotations, a custom scope for FactoryBeans so they don’t get created once per request, and autowiring by type. This makes for simple code, where the configuration lives right along where it is configured, however after a certain number of autowired beans, performance was abysmal.

Loading the main front page in Firefox, with firebug showing slowness:
baseline-firebug

Click on to read the full post.
Read the rest of this entry »

Written by Jonathan

November 28th, 2010 at 4:25 am

Posted in code, java

Tagged with

Spring Bean Autowiring into Handler/Controller Method Arguments

with 4 comments

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/

Written by Jonathan

November 20th, 2010 at 4:13 am

Posted in code, java

Tagged with

Spring Request Scoped FactoryBean returning null gets cached forever

without comments

Reading time: 2 – 4 minutes

We are using FactoryBeans extensively to own the responsibility of interesting work in constructing our object graph. These are request scoped, because they may depend on other objects that were themselves created by FactoryBeans specific to this request. For example, we have a Customer which needs an Account, so CustomerFactoryBean depends on the field Account to be injected. (We use field or setter injection because otherwise creating a factory bean that depends on another object that is created by a factory bean may create a spring exception about circular dependencies.)

package com.example.dotcom;
 
import com.example.common.Account;
import com.example.dotcom.session.CustomSession;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
 
// the scope is crucial, this controls the scope of the factory bean
@Scope("request")
public class AccountFactoryBean implements FactoryBean {
 
       // this is itself created from another factory bean
       @Autowired
       CustomSession session;
 
	@Override
	public Object getObject() throws Exception {
		// Sometimes this is going to return null, other times an instance.
                // The fix is to always return a non-null instance (despite what the
                // javadoc says). Use the Null Object pattern.
                return session.get(Account.class);
 
 
		// Note: you will need to implement caching in here or in 
		// a custom scope (which we did). Or every time you need
		// to inject the Account it will call getObject(), which
		// could be problematic if it was a slow operation.
	}
 
	@Override
	public Class getObjectType() {
		return Account.class;
	}
 
	@Override
	public boolean isSingleton() {
		return false;
	}
}

We are using autowiring by type, but we encountered a problem when the result of a factory bean’s getObject() is sometimes null. If the first call to that request scoped factory bean returned null, it would never call getObject() again in future requests. Upon investigation, you can see there is a subtle caching of null return values from factory beans. (Even if they are request scoped.) Might be a bug, I don’t know. But the work around is probably a good idea to implement anyways: use Null Objects instead of passing around null.

Here is the problematic code from Spring that caches the null return value: AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement. There is a field cached and cachedFieldValue. These are set if the value is null, and then on subsequent calls they will return the null value without calling getObject on the factory bean.

I recommend not returning null in factory beans, or else it might be cached by Spring and your factory bean will not be called again when that object is needed.

Written by Jonathan

July 27th, 2010 at 11:18 pm

Posted in code, java

Tagged with