Home > Java > Method injection with Spring

Method injection with Spring

Spring core comes out-of-the-box with two scopes: singletons and prototypes. Singletons implement the Singleton pattern, meaning there’s only a single instance at runtime (in a JVM). Spring instantiate them during context creation, caches them in the context, and serves them from the cache when needed (or something like that). Prototypes are instantiated each time you access the context to get the bean.

Problems arise when you need to inject a prototype-scoped bean in a singleton-scoped bean. Since singletons are created (and then injected) during context creation: it’s the only time the Spring context is accessed and thus prototype-scoped beans are injected only once, thus defeating their purpose.

In order to inejct prototypes into singletons, and side-by-syde with setter and constructor injection, Spring proposes another way for injection, called method injection. It works in the following way: since singletons are instantiated at context creation, it changes the way prototype-scoped are handled, from injection to created by an abstract method. The following snippet show the unsuccessful way to achieve injection:

public class Singleton {

    private Prototype prototype;

    public Singleton(Prototype prototype) {

        this.prototype = prototype;
    }

    public void doSomething() {

        prototype.foo();
    }

    public void doSomethingElse() {

        prototype.bar();
    }
}

The next snippet displays the correct code:

public abstract class Singleton {

    protected abstract Prototype createPrototype();

    public void doSomething() {

        createPrototype().foo();
    }

    public void doSomethingElse() {

        createPrototype().bar();
    }
}

As you noticed, code doesn’t specify the createPrototype() implementation. This responsibility is delegated to Spring, hence the following needed configuration:

<bean id="prototype" class="ch.frankel.blog.Prototype" scope="prototype" />

<bean id="singleton" class="sample.MySingleton">
	<lookup-method name="createPrototype" bean="prototype" />
</bean>

Note that an alternative to method injection would be to explicitly access the Spring context to get the bean yourself. It’s a bad thing to do since it completely defeats the whole Inversion of Control pattern, but it works (and is essentially the only option when a nasty bug happens on the server – see below).

However, using method injection has several main limitations:

  • Spring achieves this black magic by changing bytecode. Thus, you’ll need to have the CGLIB libraryon the classpath.
  • The feature is only available by XML configuration, no annotations (see this JIRAfor more information)
  • Finally, some application servers have bugs related to CGLIB (such as this one)

To go further:

email
Send to Kindle
  1. Colin Yates
    July 30th, 2012 at 10:26 | #1

    Actually singletons are once per instance of application context, not per runtime. I always felt this “magic” was a step too far and leads to confusion more than anything else due to its non-conformity with existing Java semantics. If I am looking at constructor injection, that tells me something about the lifecycle (one per instance). If I am looking at setter injection, that implies I can change that collaborator on that instance (although that is very often not the case due to people incorrectly preferring setter injection). Now I have a setter on a singleton which does neither?

    To solve this I always ask *why* I need different lifecycles. A common usecase is I have a container of collaborators which are needed to do some non-trivial processing, and I want to encapsulate that processing into a worker (if the worker doesn’t require collaborators then simply new it up!). So I might have (in some weird Java/Scala like syntax):

    interface (or class...) Worker(collaborator1, collaborator2, criteria) {
      Report doSomeSeriousWorkHere();
    }
    
    class SomeReportGenerator(collaborator1, collaborator2, collaborator3) {
        Report generateReport(criteria) {
            Worker worker = someWayOfGettingTheWorker...(...);
             return worker.doSomeSeriousWorkHere();
        }
    }
    

    Your suggestion would be to introduce an abstract method which spring will use to retrieve a prototype-scoped worker, already configured with the worker. I would rather introduce, for explicitness and conformance a new WorkerFactory:

    interface WorkerFactor {
        Worker createWorker();
    }
    
    class SomeReportGenerator(collaborator1, collaborator2, collaborator3, WorkerFactory) {
        Report generateReport(criteria) {
            Worker worker = this.workerFactory.createWorker();
             return worker.doSomeSeriousWorkHere();
        }
    }
    

    This also removes the common use-case of “pass-through” collaborators; collaborators injected into ComponentA simply because something ComponentA uses requires them.

    Just my thoughts :).

  2. Craig Leonard
    July 30th, 2012 at 21:52 | #2

    An alternative to this approach would be to use an ObjectFactoryCreatingFactoryBean. It abstracts the BeanFactory and prototype instance behind an instance of ObjectFactory. It does mean that you have a hard dependency on a Spring in your application logic, but I’d argue that it’s less magical than method injection.

    http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.html

  3. Chris
    April 14th, 2014 at 11:55 | #3

    Slow though :(

    .

    .

    .

  1. No trackbacks yet.