在Spring中覆盖bean的最佳方法

时间:2016-01-19 11:35:49

标签: java spring

我有一个由2个模块组成的应用程序。

其中第一个是主要的,它可以在没有安装第二个模块的情况下工作。

我的bean在主模块的beans.xml文件中定义了默认实现。当安装第二个模块时,我想保留这些bean的id,但是改变实现以使用新类。

最好的方法是什么?

第一个模块的

beans.xml

...
<bean id="myCoolService" class="com.blabla.defaultCoolServiceImpl">
...

在安装第二个模块之后,我想使用第二个模块中定义的myCoolService的实现。

UPD: Spring版本是3.2.4。 我需要做尽可能少的更改,所以我需要继续使用xml驱动的配置。

3 个答案:

答案 0 :(得分:1)

实现此目的的一种方法是通过代理,重定向到正确的实现。代理通常会重定向到默认值。如果模块2可用,它将重定向到模块2。

为了帮助代理找出可用的内容,您可能需要

  1. 始终使用&#34; name&#34;指向默认实现的成员属性。

  2. 有一种方法可以将另一个bean注册为备用实现。

  3. 例如

    MyProxy内部:

    @Autowired
    public void setDefaultWorker(Worker defaultWorker) {
        this.defaultWorker = defaultWorker;
    }
    
    private Worker defaultWorker;
    
    private Worker alternateWorker;
    
    public void registerAlternateWorker(Worker alternateWorker) {
        this.alternateWorker = alternateWorker;
    }
    
    //To use the worker
    private Worker getWorker() {
        return alternateWorker == null? defaultWorker : alternateWorker;
    }
    

    在第1单元中,您的默认实现bean应声明为具有defaultWorker作为名称

    <bean id="defaultWorker" class="MyDefaultWorkerImpl"/>
    

    模块2可以在启动时使用SmartLifeCycle将自己注册到代理注册表。

答案 1 :(得分:1)

这样做的一种方法是引入一个通用接口(我猜一个应该已经存在):

public interface MyInterface {
    //...
}

然后在主模块中使用@Service

注释默认实现
@Service
public class DefaultImplementation implements MyInterface {
    //...
}

然后,如果您的某个模块需要覆盖此实现,请使用@Primary - 注释:

@Service
@Primary
public class OverridingImplementation implements MyInterface {
    //...
}

然后,以下代码:

@Inject
private MyInterface myInterface;
如果未扫描DefaultImplementation

将注入OverridingImplementation,如果扫描,则会注入OverridingImplementation(不会抱怨多个bean)。

答案 2 :(得分:0)

如果可能,请使用:

<bean id="myCoolService" class="${IMPL_CLASS_NAME}"/>

在属性文件中定义impl类。

IMPL_CLASS_NAME=com.blabla.SecondMduleCoolServiceImpl 

或其他方法可能是:

让我们说你的defaultCoolServiceImpl和SecondMduleCoolServiceImpl实现了ICoolService接口

您可以定义这些bean和FactoryBean的实现,如下所示:

<bean id="mydefaultServiceimpl" class="com.blabla.defaultCoolServiceImpl">
<bean id="secondModuleCoolserviceimpl" class="com.blabla.SecondMduleCoolServiceImpl">
<bean id="myCoolService" class="com.blabla.ImplSelector"/>

public class ImplSelector implements FactoryBean<ICoolService>, ApplicationContextAware {
    private ApplicationContext iApplicationContext;
    // @Value("#{corePropertyConfigurer['defaultOrCool']}") you can injcet via property file.
    private String defaultOrCool = "cool" ;
    @Override
    public ICoolService getObject() throws Exception {
        if (StringUtils.equals(defaultOrCool, "default")) {
            return iApplicationContext.getBean("mydefaultServiceimpl", ICoolService.class);
        }
        return iApplicationContext.getBean("secondModuleCoolserviceimpl", ICoolService.class);
    }
    @Override
    public Class<?> getObjectType() {
        return ICoolService.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        iApplicationContext = applicationContext;
    }
}

然后你可以通过autowiring或applicationContext.getBean访问myCoolService(&#34; myCoolService&#34;,ICoolService.class);