在运行时替换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

上一篇: Replace bean at runtime

下一篇: Why does removeServerHeader work in an Azure Web App?