如何在保留参数的同时覆盖 spring bean?

How to override spring beans while keeping parameters?

我有两个项目,库和应用程序。库定义了一个 CommonService 接口,我想在应用程序中覆盖它。我使用 Spring XML 进行配置。 图书馆代码:

public interface CommonService {
  String service();
}

public class CommonServiceImpl implements CommonService {

  private String message;
  // + getter/setter

  @Override
  public String service() {
    return "Message: " + getMessage();
  }

}

申请代码:

public class OverriddenServiceImpl extends CommonServiceImpl {

  @Override
  public String service() {
    return "Overridden: " + super.service();
  }
}

库(lib-config.xml)的配置:

  <bean id="commonService" class="spring.context.test.library.CommonServiceImpl">  
    <property name="message" value="Hello!" />
  </bean>

应用程序配置(app-config.xml):

  <import resource="classpath:/lib-config.xml"/>
  <bean id="commonService" 
    class="spring.context.test.application.OverriddenServiceImpl">  
  </bean>

测试:

  @Test
  void testLibraryXML() {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/lib-config.xml");
    CommonService commonService = context.getBean("commonService", CommonService.class);
    assertEquals("Message: Hello!", commonService.service());
  }

  @Test
  void testApplicationXML() {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/app-config.xml");
    CommonService commonService = context.getBean("commonService", CommonService.class);
    // FIXME!! this gives Overridden: Message: null
    assertEquals("Overridden: Message: Hello!", commonService.service());
  }

问题出在 testApplicationXML:commonService 应该 return "Overridden: Message: Hello!",但它 returns "Overridden: Message: null".

我已将所有代码放入 github(为简单起见,库和应用程序在一个项目中): https://github.com/mateattila/spring-test-sandbox

我发现 Spring 实例化了 OverriddenServiceImpl 但没有从之前的定义中继承参数。我试过使用 bean 继承,但在这种情况下我必须使用不同的 bean id,我想避免它。我尝试使用基于注释的配置并且它有效,但它会产生大量开销(请参阅 OverriddenConfiguration 和 testApplicationAnnotation)。

关于如何用 Spring 处理这个要求有什么想法吗?我也对如何扩展 Spring 以像这样工作感兴趣。

在跟进@M.Deinum 的评论后,我找到了一个非常简单的解决方案:使用 bean 名称而不是 bean id。名称覆盖工作正常。 我已经提交了对 github repository 的修复,无论如何:

lib-config.xml:
    <bean id="commonService" name="service"
          class="spring.context.test.library.CommonServiceImpl">  
        <property name="message" value="Hello!" />
    </bean>

app-config.xml:
    <bean id="commonService2" name="service" 
          class="spring.context.test.application.OverriddenServiceImpl"
          parent="commonService">  
    </bean>

通过测试:

  @Test
  void testApplicationXML_FIXED() {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/app-config.xml");
    CommonService commonService = context.getBean("service", CommonService.class);
    assertEquals("Overridden: Message: Hello!", commonService.service());
  }