UPDATED for comment
First off, I'm not sure why you say βthis doesn't workβ for something that works fine in Spring 3.x. I suspect something must be wrong with your configuration.
It works:
- Configuration file:
@Configuration public class ServiceConfig { // only here to demo execution order private int count = 1; @Bean @Scope(value = "prototype") public TransferService myFirstService(String param) { System.out.println("value of count:" + count++); return new TransferServiceImpl(aSingletonBean(), param); } @Bean public AccountRepository aSingletonBean() { System.out.println("value of count:" + count++); return new InMemoryAccountRepository(); } }
- test file to run:
@Test public void prototypeTest() { // create the spring container using the ServiceConfig @Configuration class ApplicationContext ctx = new AnnotationConfigApplicationContext(ServiceConfig.class); Object singleton = ctx.getBean("aSingletonBean"); System.out.println(singleton.toString()); singleton = ctx.getBean("aSingletonBean"); System.out.println(singleton.toString()); TransferService transferService = ctx.getBean("myFirstService", "simulated Dynamic Parameter One"); System.out.println(transferService.toString()); transferService = ctx.getBean("myFirstService", "simulated Dynamic Parameter Two"); System.out.println(transferService.toString()); }
Using Spring 3.2.8 and Java 7 produces this output:
value of count:1 com.spring3demo.account.repository.InMemoryAccountRepository@4da8692d com.spring3demo.account.repository.InMemoryAccountRepository@4da8692d value of count:2 Using name value of: simulated Dynamic Parameter One com.spring3demo.account.service.TransferServiceImpl@634d6f2c value of count:3 Using name value of: simulated Dynamic Parameter Two com.spring3demo.account.service.TransferServiceImpl@70bde4a2
Thus, the "Singleton" Bean is requested twice. However, as you would expect, Spring creates it only once. The second time, he sees that he has a Bean and simply returns an existing object. The constructor (@Bean method) is not called a second time. As a sign of respect, when a 'Prototype' Bean request is requested from the same context object twice, we see that the link changes the output AND, that the constructor method (@Bean) is called twice.
So, the question is how to introduce a singleton into a prototype. The configuration class above shows how to do this! You must pass all such references to the constructor. This will allow the created class to be pure POJO, as well as make the contained reference objects immutable, as it should be. Thus, the transfer service might look something like this:
public class TransferServiceImpl implements TransferService { private final String name; private final AccountRepository accountRepository; public TransferServiceImpl(AccountRepository accountRepository, String name) { this.name = name;
If you write Unit Tests, you will be so happy that you created classes without any @Autowired. If you need stand-alone components, save them in java configuration files.
This will call the method below in BeanFactory. Pay attention to the description of how this is intended for your specific use case.
Object getBean(String name, Object... args) throws BeansException;