stella
stella

Reputation: 2596

Spring's method injection

I'm reading the Spring current version's documentation and have problems with understanding of the chapter 5.4.6 Method Injection. As far as I got we can provide the ability of recreation a bean every time we call the method using the bean. Documentation provides the following code example:

public class CommandManager implements ApplicationContextAware {

    //Imports and comments were omitted
    private ApplicationContext applicationContext;

    public Object process(Map commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    protected Command createCommand() {
        return this.applicationContext.getBean("command", Command.class);
    }

    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

where ApplicationContextAware interface looks like:

public interface ApplicationContextAware {

    //JavaDocs ommited
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;

}

So, what is the method public Object process(Map commandState)? Is it a callback? If so, where is it going to be called and who performs that call? After all, it's not clear why the bean is goign to be recreated every time it needed.

Upvotes: 0

Views: 142

Answers (3)

Alexey
Alexey

Reputation: 41

According to Spring's suggestion

A solution is to forego some inversion of control. You can make bean A aware of the container by implementing the ApplicationContextAware interface, and by making a getBean("B") call to the container ask for (a typically new) bean B instance every time bean A needs it.

solution for method get() could look like this:

public class SingletonA implements ApplicationContextAware {
        
        private ApplicationContext applicationContext;
    
        public PrototypeB getPrototypeB() {
            return applicationContext.getBean("prototypeB",PrototypeB.class);
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    }

with beans defenition

<bean id="singletonA" class="di.methodinjection.SingletonA" autowire="byName"/>
<bean id="prototypeB" class="di.methodinjection.PrototypeB" scope="prototype"/>

Upvotes: 0

beerbajay
beerbajay

Reputation: 20270

The Command and CommandManager classes are just example classes, where process() is a part of that example. They have nothing to do with ApplicationContextAware.

Note the comment in the example for CommandManager:

// a class that uses a stateful Command-style class to perform some processing

process() is to be called by the application, somewhere else; it doesn't matter for the sake of the example. If you are not using exactly the same model in your code, you should ignore this method and just call applicationContext.getBean() where applicable.

Finally, yes CommandManager should be registered as a bean in order for spring to call setApplicationContext().

edit

why does spring know that it have to recreate the bean with the name command every time

Given the contents of the example, it doesn't. The example code calls getBean(), which, according to the javadocs:

Return an instance, which may be shared or independent, of the specified bean.

In order to ensure that you always get a new instance, you'll need to use the prototype scope.

<bean id="beanB class="Command" scope="prototype"/>

Upvotes: 2

Igor Konoplyanko
Igor Konoplyanko

Reputation: 9374

Injection is happening actually here:

protected Command createCommand() {
    // notice the Spring API dependency!
    return this.applicationContext.getBean("command", Command.class);
}

We are just getting bean with different lifecycle in this method.

Upvotes: 1

Related Questions