在运行时替换bean
代码库是典型的基于Spring的企业代码库,大约有150万行代码。 我们有不少的春天上下文文件。 下面的测试是一个问题。
对于测试用例,我创建了另一组测试文件(主要是导入相关的项目spring上下文),并且少数bean包含用于外部服务的mocked bean。 所有的测试类都使用相同的上下文配置文件集,而且事情发生的时间是90%。
但在某些情况下,我会嘲笑一个豆子。 但是我不希望编辑spring-text.xml(因为它会干扰所有的类),我也不希望为每个测试类分别设置一组xml。 一个非常简单的说法是:
@Autowired
@Qualifier("fundManager")
FundManager fundManager;
@Test
public void testSomething(){
TransactionManager tx = mock(TransactionManager.class);
fundManager.setTransactionManager(tx);
//now all is well.
}
这在某些情况下有效。 但是有时候,希望这个新的临时bean tx
应该设置在所有跨代码库使用TransactionManager
bean的地方。
代理类恕我直言不是一个很好的解决方案,因为我将不得不用一个包装包装所有的bean。 这就是我理想的目标:
@Test
public void testSomething(){
TransactionManager tx = mock(TransactionManager.class);
replace("transactionManagerBean",tx);
//For bean with id:transactionManagerBean should be replace with `tx`
}
BeanPostProcessor
看起来像一个替代的建议,但我遇到了一些打嗝。
想象一下,你有bean A注入bean B:
public static class A {
}
public static class B {
@Autowired
private A a;
@Override
public String toString() {
return "B [a=" + a + ']';
}
}
和春天上下文初始化您的应用程序:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:annotation-config/>
<bean id="a" class="test.Test$A"/>
<bean id="b" class="test.Test$B"/>
</beans>
然后下面的代码片段将替换上下文中的所有bean A:
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml");
System.out.println(ctx.getBean("b"));
final A replacement = new A();
for (String name : ctx.getBeanDefinitionNames()) {
final Object bean = ctx.getBean(name);
ReflectionUtils.doWithFields(bean.getClass(),
field -> {
field.setAccessible(true);
field.set(bean, replacement);
},
// Here you can provide your filtering.
field -> field.getType().equals(A.class)
);
}
System.out.println(ctx.getBean("b"));
}
这个例子是用Java 8 + Spring 4.1编写的。 不过,修改Java和Spring老版本的代码会很简单。
链接地址: http://www.djcxy.com/p/88217.html