在使用Spring 3.1编写集成测试时,我通常将request
范围定义为SimpleThreadScope
,并使用以下XML上下文配置:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope" />
</entry>
</map>
</property>
</bean>
要定义request
范围实现支持的prototype
范围,我想将类更改为prototype
范围的实现。但是我无法找到任何。
查看Scope Interface Javadoc,在所有已知实现类的部分中,我看到列出:AbstractRequestAttributesScope, PortletContextScope, RequestScope, ServletContextScope, SessionScope, SimpleThreadScope...
没有看起来像原型范围。
如何将请求范围定义为集成测试的原型?
更新:我已经设法通过创建我自己的原型范围来完成集成测试,我已经定义如下,所以现在我的问题是,以下实现是否正确,或者它必须修复。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class PrototypeScope implements Scope {
private static final Log logger = LogFactory.getLog(PrototypeScope.class);
public Object get(String name, ObjectFactory objectFactory) {
return objectFactory.getObject();
}
public Object remove(String name) {
return null;
}
public void registerDestructionCallback(String name, Runnable callback) {
logger.warn("PrototypeScope does not support destruction callbacks. "
+ "Consider using a RequestScope in a Web environment.");
}
public Object resolveContextualObject(String key) {
return null;
}
public String getConversationId() {
return Thread.currentThread().getName();
}
}
更新2:我正在使用TestNG,我的集成测试如下所示:
@Test
@ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
@Resource
private MyBeanThatShouldBePrototype bean;
@Transactional
public void testCase() {
...
答案 0 :(得分:2)
实际上它以不同的方式工作 - Spring检查bean是否是原型,然后克隆其定义并只填充新bean,因此没有用于保存这些bean的支持类。如果您想查看实施,请访问:
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean
你会发现:
if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
如果要在测试中使用原型范围,可以通过调用新的MyObjectThatShouldBePrototype()手动创建此bean,然后使用AutowireCapableBeanFactory(注入/自动连接到测试中)将其配置为Spring bean:
@Autowired
AutowireCapableBeanFactory beanFactory;
public MyObjectThatShouldBePrototype getBean() {
MyObjectThatShouldBePrototype bean = new MyObjectThatShouldBePrototype();
beanFactory.autowireBean(bean);
return bean;
}
当然有几种创建bean的方法 - 你可以在http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
找到答案 1 :(得分:1)
这样的事情不适合你吗?
@Test
@ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" },
classes = MyIntegrationTest.TestConfig.class)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
@Resource
private MyBeanThatShouldBePrototype bean; // protype bean produced by spring
@Transactional
public void testCase() {
...
}
@Configuration
public static class TestConfig {
@Bean
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public MyBeanThatShouldBePrototype myBeanThatShouldBePrototype() {
return new MyBeanThatShouldBePrototype();
}
}
}
答案 2 :(得分:0)
也许你可以采取另一种方式?
如何编写一个将请求范围的bean候选者更改为原型的beanfactorypostprocessor呢?
我自己没有尝试过,但你应该能够将它应用于声明为请求作用域的任何bean并设置原型标志。
在单元测试的spring上下文中,您定义了此处理器,并且在集成测试的上下文中,此后处理器不会出现。