簡體   English   中英

在Spring上重新注冊singleton bean

[英]Re-registering singleton bean on Spring

我有一個多模塊項目,每個模塊都有自己的單元測試,並為該模塊的類提供模擬。

我正在嘗試構建一個應用程序上下文,其中每個模塊都可以定義自己的模擬,但后來的單元測試將能夠覆蓋這些模擬,例如:

public class Test {

    private static final class StupidMock {
    }

    @org.junit.Test
    public void test() {
        StaticApplicationContext applicationContext = new StaticApplicationContext();
        final ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        StupidMock stupidMock = new StupidMock();  // original mock
        beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock);

        StupidMock f1 = applicationContext.getBean(StupidMock.class);
        if (f1 == null || f1 != stupidMock) {  // ensuring mock is retrievable
            fail("Could not get bean");
        }

        for (String names2Remove : beanFactory.getBeanNamesForType(StupidMock.class)) {
            applicationContext.removeBeanDefinition(names2Remove);  // <-- fails here 
        }

        StupidMock stupidMock2 = new StupidMock();     // replacement mock
        beanFactory.registerSingleton(StupidMock.class.getName(), stupidMock2);
    }
}

問題是這個簡單的片段在嘗試刪除第一個模擬時失敗,聲稱沒有這樣的bean(盡管Spring剛剛成功地為我提供了一個名字)。

如果我只是嘗試在第一個上面注冊另一個模擬,Spring抱怨說已經存在對象限制。

DefaultSingletonBeanRegistry有一個受保護的removeSingleton方法,但是我無法控制StaticApplicationContext擁有的bean工廠。 我可以使用反射並且無論如何都要調用這個受保護的方法,但是對於這樣一個簡單的任務來說這樣做是錯誤的。

我究竟做錯了什么? 如何在StaticApplicationContext上實現單例替換?

這里的問題是registerSingleton方法實際上沒有創建相應的BeanDefinition ,它只是注冊實例化的單例,將它與你提供的名稱相關聯,然后通過應用程序上下文檢索它 - 盡管它沒有底層的BeanDefinition。

所以當你調用applicationContext.removeBeanDefinition(names2Remove); 它失敗,因為沒有bean定義 ,只有已注冊的完全實例化的bean。

修復是不使用registerSingleton,而是使用一個使用BeanDefinition的registerSingleton形式:

Map<String, String> map = new HashMap<String, String>();
map.put("i", "10"); // set all the properties for the mock..
MutablePropertyValues propertyValues = new MutablePropertyValues(map);

beanFactory.registerSingleton(StupidMock.class.getName(), StupidMock.class, propertyValues);

您可以使用spring-reinject重新定義bean。

如果您使用的是spring框架,為什么不使用Spring測試框架

您可以使用以下注釋在每個單元測試的基礎上進行特定的模擬

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM