每个评论已更新
首先,我不确定您为什么对在Spring 3.x中可以正常使用的内容说“这不起作用”。我怀疑您的配置在某处一定有问题。
这有效:
-配置文件:
@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
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());
}
使用Spring 3.2.8和Java 7,可以得到以下输出:
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
因此,两次请求“ Singleton” Bean。但是,正如我们期望的那样,Spring仅创建一次。第二次看到它拥有该bean,并仅返回现有对象。构造函数(@Bean方法)不再被调用。与此不同,当从同一个上下文对象两次请求“原型” Bean时,我们看到引用在输出中发生了变化,并且构造函数(@Bean方法)被调用了两次。
因此,问题是如何将单例注入原型。上面的配置类也说明了如何做到这一点!您应该将所有此类引用传递给构造函数。这将使创建的类成为纯POJO,并使所包含的引用对象保持原样不变。因此,转移服务可能类似于:
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;
}
....
}
如果编写单元测试,您会很高兴在没有所有@Autowired的情况下创建了此类。如果确实需要自动装配的组件,请将其保留在Java配置文件的本地。
这将在BeanFactory中调用下面的方法。请在描述中注意这是如何用于您的确切用例的。
/**
* Return an instance, which may be shared or independent, of the specified bean.
*
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;