javaspring

Spring Prototype scoped bean in a singleton


I am trying to inject a prototype bean in a singleton bean such that every new call to a singleton bean method has a new instance of the prototype bean.

Consider a singleton bean as below:

    @Component
    public class SingletonBean {
       @Autowired 
       private PrototypeBean prototypeBean;

       public void doSomething() {
         prototypeBean.setX(1);
         prototypeBean.display();
       }
    }

I expect that every time the doSomething() method is called, a new PrototypeBean instance is utilized.

Below is the prototype bean:

     @Component 
     @Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
     public class PrototypeBean {
        Integer x;

        void setX(Integer x) {
         this.x = x;
        }

        void display() {
          System.out.println(x);
        }
    }

What seems to be happening is that spring is being overeager in handing over a new instance of PrototypeBean in the doSomething() method. That is, the 2 lines of code in the doSomething() method are creating a new instance of prototypeBean in each line.

And so in the 2nd line - prototypeBean.display() prints NULL.

What is missing in configuration for this injection?


Solution

  • From Spring documentation:

    You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes. If you try to create a scoped proxy for a singleton bean, the BeanCreationException is raised.

    It seems the documentation has changed a bit for version 3.2 documentation where you can find this sentence:

    You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes.

    It seems that its not expected you use a proxied prototype bean, as each time it is requested to the BeanFactory it will create a new instance of it.


    In order to have a kind of factory for your prototype bean you could use an ObjectFactory as follows:

    @Component
    public class SingletonBean {
    
        @Autowired
        private ObjectFactory<PrototypeBean> prototypeFactory;
    
        public void doSomething() {
            PrototypeBean prototypeBean = prototypeFactory.getObject();
            prototypeBean.setX(1);
            prototypeBean.display();
        }
    }
    

    and your prototype bean would be declared as follows:

    @Component 
    @Scope(value="prototype")
    public class PrototypeBean {
        // ...
    }