Bean marked with prototype scope not working in Spring

9.4k Views Asked by At

I have two beans, Parent and Child. Child bean I have declared as of Protoype scope.
I want new child object is used to call any child's method in the Parent class. For eg. in the below example,I want statement 1 calls method sayHi on different child object and statement 2 calls sayHi1 on different child object.

One way is to implement ApplicationContextAware and get new child object using context.getBean("") before calling any child's method. But i don't want to do that.

Is there any other alternative?

@Component
public class Parent{

    @Autowired
    Child child;

    public void sayHello(){     
        child.sayHi();           -------------- (1)
    }

    public void sayHello1(){    
        child.sayHi1();          --------------- (2)
    }
}

@Component
@Scope(value=BeanDefinition.SCOPE_PROTOTYPE)
public class Child{

    public void sayHi(){
        System.out.println("Hi Spring 3.0");

    }

    public void sayHi1(){
        System.out.println("Hi1 Spring 3.0 ");      
    }

}
5

There are 5 best solutions below

0
On

The fix is simply to mark the prototype bean as a scoped proxy, what this means is that a when you inject a bean of a smaller scope into a larger scope(like in your case where a prototype is injected into a singleton) then a proxy of the bean will be injected into the larger scope and when methods of the bean are invoked via proxy, the proxy understands the scope and will respond appropriately.

@Component
@Scope(value=BeanDefinition.SCOPE_PROTOTYPE, proxyMode=ScopedProxyMode.TARGET_CLASS)
public class Child{

Here is a reference

Another option could be to use something called lookup method injection described here

0
On

Prototype scope means Spring will give you a new Child object each time you ask for one (via injection or an explicit bean retrieval from an app context). In your Parent class, you only asked for a Child once, so you only got one. If you want two different Child objects in your Parent, then autowire two:

@Component
public class Parent{

    @Autowired
    Child child;

    @Autowired
    Child child1;

    public void sayHello(){     
        child.sayHi();
    }

    public void sayHello1(){    
        child1.sayHi1();
    }
}
0
On

I think you have to make a new Child yourself each time or indeed use the spring context to get a fresh bean.

Spring will only create a new instance when it needs to inject something (in case of prototype). When you are in a class you are effectively out of the scope of spring.

Here is a similar post: @Scope("prototype") bean scope not creating new bean

http://static.springsource.org/spring/docs/3.0.0.M3/reference/html/ch04s04.html#beans-factory-scopes-prototype Parts 4.4.2 and 4.4.3 are relevant.

0
On

You can't do it. After the ApplicationContext is up, only one bean will be injected into child. For each parent a new child will be created.

The thing is a parent have only one child, so your 2 methods will invoke only that child methods.

What exactly you are trying to achieve? I am sure there is a proper solution for it.

0
On

Answers are already given by others, I will include a theory which can be helpful

To turn component to prototype we do this - You probably already know this :)

@Scope(value=BeanDefinition.SCOPE_PROTOTYPE)
Class B{ .....}

This will only help if the class B is called as .getBean(B.class) OR the class Autowiring it is also a Prototype.


Now ,suppose we do like this

 @Component
    Class A{
   
          @Autowired
          Class B;
     }
   

Class A is singleton and it assumes every instance of class B as Singleton too : |


Now, how to tell class A that class B is Prototype?

Simple, just include proxyMode=ScopedProxyMode.TARGET_CLASS and class A will know that class B is Prototype !

It will look something like below :

@Component
@Scope(value=BeanDefinition.SCOPE_PROTOTYPE, proxyMode=ScopedProxyMode.TARGET_CLASS)
public class B{.....}