每条评论更新
首先,我不确定你为什么说“这不起作用”,因为在 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.
* <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;