Spring 如何覆盖测试的作用域bean?

Spring 如何覆盖测试的作用域bean?,spring,proxy,scope,javabeans,Spring,Proxy,Scope,Javabeans,我的Spring Java配置中有一个bean: @Bean @Scope( proxyMode=ScopedProxyMode.TARGET_CLASS, value=SpringScopes.DESKTOP ) public BirtSession birtSession() { return new BirtSession(); } 对于测试,我需要一个没有作用域的模拟(测试中没有“桌面”作用域)。但当我为我的测试创建一个配置时,该配置导入上述配置并包含: @Bean publi

我的Spring Java配置中有一个bean:

@Bean
@Scope( proxyMode=ScopedProxyMode.TARGET_CLASS, value=SpringScopes.DESKTOP )
public BirtSession birtSession() {
    return new BirtSession();
}
对于测试,我需要一个没有作用域的模拟(测试中没有“桌面”作用域)。但当我为我的测试创建一个配置时,该配置导入上述配置并包含:

@Bean
public BirtSession birtSession() {
    return new MockSession();
}
我得到一个“桌面”范围的模拟bean:-(

我如何让Spring“忘记”这个
@Scope
注释


PS:当我不使用Import和copy&paste时,它可以工作,但我不想这样做。

问题不是Spring保留注释,问题是Spring首先尝试解析“有效的”为了做到这一点,它检查作用域是否可用。Spring急切地检查作用域。因此它永远不会进入第二个/重写bean定义

创建虚拟作用域:

import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;

public class MockSpringScope implements org.springframework.beans.factory.config.Scope {

    private Map<String, Object> objects = new HashMap<String, Object>();

    @Override
    public Object get( String name, ObjectFactory<?> objectFactory ) {
        Object result = objects.get( name );
        if( null == result ) {
            result = objectFactory.getObject();
            objects.put( name, result );
        }
        return result;
    }

    @Override
    public Object remove( String name ) {
        return objects.remove( name );
    }

    @Override
    public void registerDestructionCallback( String name, Runnable callback ) {
        // NOP
    }

    @Override
    public Object resolveContextualObject( String key ) {
        // NOP
        return null;
    }

    @Override
    public String getConversationId() {
        // NOP
        return null;
    }

}
import java.util.HashMap;
导入java.util.Map;
导入org.springframework.beans.factory.ObjectFactory;
公共类MockSpringScope实现org.springframework.beans.factory.config.Scope{
私有映射对象=新HashMap();
@凌驾
公共对象获取(字符串名称,ObjectFactory ObjectFactory){
对象结果=objects.get(名称);
if(null==结果){
结果=objectFactory.getObject();
对象。放置(名称、结果);
}
返回结果;
}
@凌驾
公共对象删除(字符串名称){
返回对象。删除(名称);
}
@凌驾
public void registerDestructionCallback(字符串名称,可运行回调){
//不
}
@凌驾
公共对象ResolveContextaObject(字符串键){
//不
返回null;
}
@凌驾
公共字符串getConversationId(){
//不
返回null;
}
}

并将其注册为“桌面”作用域。这将允许Spring成功解析生产配置。

问题似乎出现在使用
ScopedProxy Creator.CreateScopeProxy()的
ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod()
创建作用域bean定义的静态方法:

// replace the original bean definition with the target one, if necessary
        BeanDefinition beanDefToRegister = beanDef;
        if (proxyMode != ScopedProxyMode.NO) {
            BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
                    new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
            beanDefToRegister = proxyDef.getBeanDefinition();
    }
由于
BeanDefinitionHolder
返回的是
RootBeanDefinition
而不是
ConfigurationClassBeanDefinition
,所以作用域代理bean定义(即
ScopedProxyFactoryBean
)不能被另一个Java配置类覆盖


一种解决方法可能是在xml配置文件中声明要覆盖的作用域bean,并使用
@ImportResource导入它。

您正在编写什么类型的测试?单元测试?注释mocked
birtSession()怎么样
@Primary
?一些
桌面
作用域必须可用,但自动连线将始终选择您的主bean。@JBNizet:是的,这是一个JUnit测试,使用
SpringJUnit4ClassRunner
,您真的需要一个Spring容器,还是不能简单地实例化测试中的类并注入模拟依赖项dencies手动?听起来像是一个bug/功能。这是故意的还是我应该将其报告为bug?我认为这是一个bug。ConfigurationClassBeanDefinitionReader不应该注册RootBeanDefinitions,因为它有自己的BeanDefinition类来确定bean定义是否是在外部创建的。我觉得您应该报告此bug因为你似乎知道你在说什么:-)请在回答中添加URL,或者在你添加URL后作为评论。这很快:修复为3.2.2!非常感谢:-)