[英]Refresh/rebuild specific beans during Spring integration testing
Our existing Spring Boot integration setup was using @DirtiesContext
to rebuild the entire bean pool in-between different test methods. 我们现有的Spring Boot集成设置使用
@DirtiesContext
在不同的测试方法之间重建整个bean池。
This was fairly slow, and so we started working with beans that could be "refreshed" or torn down/rebuild internally without re-creating the instance. 这是相当缓慢的,所以我们开始与豆可能被“刷新”或推倒/ 内部重建,而无需重新创建实例工作。
The problem is that only some beans support this. 问题是只有一些bean支持这一点。 If we control
UsersBean
, we can implement a UsersBean.refresh()
method and call it in our @After
method. 如果我们控制
UsersBean
,我们可以实现UsersBean.refresh()
方法并在我们的@After
方法中调用它。
But if we have existing beans/classes that don't support refreshing, or we don't control, how can we conditionally indicate that certain beans need to be dirtied/rebuilt after a specific test? 但是,如果我们现有的bean /类不支持刷新,或者我们无法控制,那么我们如何有条件地指出某些bean在特定测试后需要弄脏/重建?
Or more succinctly: Is there a way to mark as dirty a subsection of your bean pool, for rebuilding, at the end of a test method? 或者更简洁:在测试方法结束时,有没有办法将bean池的子部分标记为脏,用于重建?
It looks like this is possible, at least within a Spring Boot environment. 看起来这是可能的,至少在Spring Boot环境中是这样。 The
ApplicationContext
implementation there is a GenericApplicationContext which has the ability to removeBeanDefinition() , which can then be re-registered via registerBeanDefinition() . ApplicationContext
实现有一个GenericApplicationContext ,它具有removeBeanDefinition()的能力,然后可以通过registerBeanDefinition()重新注册。
This even cascades through to remove beans that hold a reference to the bean that's being removed (the implementation of this can be seen in DefaultSingletonBeanRegistry.destroyBean() ). 这甚至可以级联删除bean,这些bean包含对正被删除的bean的引用(可以在DefaultSingletonBeanRegistry.destroyBean()中看到它的实现)。
For example if Bean1
is referenced by Bean2
: 例如,如果
Bean1
引用Bean2
:
@Component
public class Bean1 {
}
@Component
public class Bean2 {
@Autowired
public Bean1 bean1;
}
Then a test can remove bean1
from the context, and see bean2
replaced as well: 然后测试可以从上下文中删除
bean1
,并且看到bean2
被替换:
@RunWith(SpringRunner.class)
public class BeanRemovalTest implements ApplicationContextAware {
@Autowired
private Bean1 bean1;
@Autowired
private Bean2 bean2;
private ApplicationContext applicationContext;
@Test
public void test1() throws Exception {
System.out.println("test1():");
System.out.println(" bean1=" + bean1);
System.out.println(" bean2.bean1=" + bean2.bean1);
resetBean("bean1");
}
@Test
public void test2() throws Exception {
System.out.println("test2():");
System.out.println(" bean1=" + bean1);
System.out.println(" bean2.bean1=" + bean2.bean1);
}
private void resetBean(String beanName) {
GenericApplicationContext genericApplicationContext = (GenericApplicationContext) applicationContext;
BeanDefinition bd = genericApplicationContext
.getBeanDefinition(beanName);
genericApplicationContext.removeBeanDefinition("bean1");
genericApplicationContext.registerBeanDefinition("bean1", bd);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
This shows both bean instances being replaced: 这显示了两个bean实例被替换:
test1():
bean1=hello.so.Bean1@61d6015a
bean2.bean1=hello.so.Bean1@61d6015a
test2():
bean1=hello.so.Bean1@2e570ded
bean2.bean1=hello.so.Bean1@2e570ded
(If the resetBean("bean1")
is commented out, it is the same instance both times round). (如果
resetBean("bean1")
被注释掉,那么两次都是相同的实例)。
There are bound to be edges where this doesn't work out - eg if another bean is holding onto a reference obtained from ApplicationContext.getBean()
. 必然存在这样的边缘 - 例如,如果另一个bean持有从
ApplicationContext.getBean()
获得的引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.