Announcement Announcement Module
Collapse
No announcement yet.
Reusing the same instance of a prototype bean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Reusing the same instance of a prototype bean

    In the following example, how would I have myMainService and barService, which are themselves both prototype scoped, to refer to the same instance of fooService? (I've kept these beans stateless to keep the example small, just assume that they all have state)

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    	<bean	id="myMainService" class="com.example.spring.MyMainService"
    		autowire="constructor" scope="prototype"/>
    
    	<bean 	id="fooService" class="com.example.spring.FooService" scope="prototype"/>
    			
    	<bean 	id="barService" class="com.example.spring.BarService"
    		autowire="constructor" scope="prototype"/>
    </beans>
    Code:
    public class Main {
    	public static void main(String[] args) {
    		GenericXmlApplicationContext applicationContext =
    			new GenericXmlApplicationContext("classpath:/applicationContext.xml");
    		applicationContext.getBean(MyMainService.class).sayHello();
    	}
    }
    
    class MyMainService {
    	private final FooService foo;
    	private final BarService bar;
    	
    	public MyMainService(FooService foo, BarService bar) {
    		this.foo = foo;
    		this.bar = bar;
    	}
    
    	public void sayHello() {
    		// how do I have MyMainService and BarService
    		// to refer to the same instance of FooService?
    		System.out.println(foo);
    		bar.print();
    	}
    }
    
    class FooService {}
    
    class BarService {
    	private final FooService foo;
    
    	public BarService(FooService foo) {
    		this.foo = foo;
    	}
    	
    	public void print() {
    		System.out.println("Bar has " + foo);
    	}
    }

  • #2
    The goal of prototype scope is to just have each bean depending on the prototype actually gets a different instance... Maybe you should not use prototype in this case.

    However, there might be a tricky solution to your problem. Define a new bean that has a dependency on your prototype bean, and that exposes that instance (with a getter); you can refer to it as the "single prototype provider"; this bean is singleton-scoped. Then let your MyMainService and BarService both depend on the provider. In the setter method (or other injection method) of both MyMainService and BarService, get the FooService from the provider using the exposed property and initialize the corresponding instance variable. As a result, both MyMainService and BarService will refer to the same FooService instance.

    Code:
    <bean id="myMainService" ...>
      <property name="fooProvider" ref="provider"/>
    </bean>
    <bean id="barService" ...>
      <property name="fooProvider" ref="provider"/>
    </bean>
    
    <bean id="fooService" .../>
    <bean id="provider" class="SingleFooProvider" scope="singleton">
      <property name="foo" ref="fooService"/>
    </bean>
    Define the classes as follows:
    Code:
    class SingleFooProvider {
      private FooService foo; + get/set
    }
    
    class MyMainService {
      private FooService foo;
      public void setFooProvider(SingleFooProvider provider) {
        foo = provider.getFoo();
      }
    }
    
    class BarService {
      private FooService foo;
      public void setFooProvider(SingleFooProvider provider) {
        foo = provider.getFoo();
      }
    }
    Since the same SingleFooProvider is injected into MyMainService and BarService, the same FooService is stored into both MyMainService.foo and BarService.foo.

    You should however not overuse this mechanism, as it creates some kind of mixed singleton-prototype ServiceLocator (the "single prototype provider") into the application context. This is somehow abusing the prototype scope pattern. Further, the provider class does not make sense in terms of your business. This is clearly technical access code that gets mixed with your business code configuration.

    Comment

    Working...
    X