Autowiring prototypes

One thing that’s always annoyed me about using the @Autowired annotation to configure Spring beans is that the standard interface for instantiating prototype beans is not refactoring-friendly.

For example, if you want to instantiate this prototype bean using getBean()

@Scope("prototype")
@Component
public class SendMessageCommand {
	private Mail message;

	@Autowired
	StatusReporter statusReporter;

	public SendMessageCommand(Mail message) {
		this.message = message;
	}
}

you need to pass in the arguments to the constructor as an array of objects as follows.

@Autowired
Spring spring;

SendMessageCommand sendMessageCommand = spring.getBean(SendMessageCommand.class,
				new Object[] { message });

Spring is a helper class that looks like this:

@Service
public class Spring {
	@Autowired
	private ApplicationContext context;

	@SuppressWarnings("unchecked")
	public <T> T getBean(Class<? extends T> type, Object[] args) {
		String beanName = type.getSimpleName();
		beanName = beanName.substring(0, 1).toLowerCase()
				+ beanName.substring(1);
		return (T) context.getBean(beanName, args);
	}
}

I was using this syntax all over my open source project whenever I needed to inject services into my prototype beans.

Finally I got fed up with my getBean() calls getting ignored when I refactored my constructors so I dug a little deeper and discovered a solution!

Now my Spring class looks like this:

public class Spring {
	@Autowired
	private ApplicationContext context;

	public <T> T autowire(T existingBean)
	{
		context.getAutowireCapableBeanFactory().autowireBean(existingBean);
		return existingBean;
	}
}

and instead of calling getBean() to instantiate my prototype, I do this:

@Autowired
Spring spring;

SendMessageCommand sendMessageCommand = spring.autowire(new SendMessageCommand( message ));

Yay! @Autowire refactorable prototype beans!

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply