UPDATED per comment
First, I'm not sure why you say "this does not work" for something that works just fine in Spring 3.x. I suspect something must be wrong in your configuration somewhere.
This works:
-- Config 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 execute:
@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, gives 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
So the 'Singleton' Bean is requested twice. However as we would expect, Spring only creates it once. The second time it sees that it has that bean and just returns the existing object. The constructor (@Bean method) is not invoked a second time. In deference to this, when the 'Prototype' Bean is requested from the same context object twice we see that the reference changes in the output AND that the constructor (@Bean method) IS invoked twice.
So then the question is how to inject a singleton into a prototype. The configuration class above shows how to do that too! You should pass all such references into the constructor. This will allow the created class to be a pure POJO as well as making the contained reference objects immutable as they should be. So the transfer service might look something like:
public class TransferServiceImpl implements TransferService {
private final String name;
private final AccountRepository accountRepository;
public TransferServiceImpl(AccountRepository accountRepository, String name) {
this.name = name;
// system out here is only because this is a dumb test usage
System.out.println("Using name value of: " + this.name);
this.accountRepository = accountRepository;
}
....
}
If you write Unit Tests you will be ever so happy you created the classes this without all the @Autowired. If you do need autowired components keep those local to the java config files.
This will call the method below in the BeanFactory. Note in the description how this is intended for your exact use case.
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>Allows for specifying explicit constructor arguments / factory method arguments,
* overriding the specified default arguments (if any) in the bean definition.
* @param name the name of the bean to retrieve
* @param args arguments to use if creating a prototype using explicit arguments to a
* static factory method. It is invalid to use a non-null args value in any other case.
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no such bean definition
* @throws BeanDefinitionStoreException if arguments have been given but
* the affected bean isn't a prototype
* @throws BeansException if the bean could not be created
* @since 2.5
*/
Object getBean(String name, Object... args) throws BeansException;