【问题标题】:Can I override a spring bean definition defined using classpath scan?我可以覆盖使用类路径扫描定义的 spring bean 定义吗?
【发布时间】:2017-01-04 10:25:15
【问题描述】:

我有一个应用程序,它具有一个非常简单的插件架构,通过使用 spring 类路径扫描注册附加行为(“安装”插件通过将 plugin.jar 放在类路径上发生)。

这对于注册额外的 bean 非常有用,并且对于注册这样的钩子也非常有用:

// core.jar:
@Component
class CoreClass {
  public void addListener(Listener listener) { /* ... */ }
}

// plugin.jar
@Component
class Plugin {
  public Plugin(CoreClass coreClass) {
    coreClass.addListener(new PluginListener());
  }
}

但有时替换整个 bean 更合适。这可能看起来像这样:

// core.jar:
@Component("someBean")
class CoreClass implements CoreInterface {
  @Override
  public void doStuff();
}

// plugin.jar
@Component("someBean")
@Order(HIGHEST_PRECEDENCE)
class Plugin implements CoreInterface {
  @Override
  public void doStuff();
}

在这种情况下,我希望在启动期间通过类路径扫描发现 PluginCoreClass,但是应该忽略 CoreClass,因为 bean someBean 有另一个具有更高优先级的定义。

我知道我可以使用 XML (<import resource="classpath*:plugin-spring.xml" />) 来做到这一点,因为 XML 允许覆盖定义。但这也可以使用注解吗?

编辑:请注意,有时我会基于名称注入多个相同类型(具有不同属性)的 bean 实例。因此,我实际上需要用某个名称覆盖 bean。

【问题讨论】:

    标签: java spring plugins


    【解决方案1】:

    可能使用的解决方案:

    @Primary

    表示当多个候选者有资格自动装配单值依赖项时,应优先考虑 bean。如果候选中恰好存在一个“主”bean,它将是自动装配的值。

    这个注解在语义上等同于 Spring XML 中元素的主要属性。

    可用于任何直接或间接使用@Component 注释的类或使用@Bean 注释的方法。

    // core.jar:
    @Component
    class CoreClass implements CoreInterface {
      @Override
      public void doStuff();
    }
    
    // plugin.jar
    @Component
    @Primary
    class Plugin implements CoreInterface {
      @Override
      public void doStuff();
    }
    

    http://memorynotfound.com/handling-multiple-autowire-candidates-with-spring-primary/

    或者你可以使用:

    @Configuration  
    @ImportResource( { "classpath*:core-spring.xml", "classpath*:plugin-spring.xml" } )  
    public class ConfigClass { } 
    

    我怀疑注释的问题不清楚要覆盖哪个顺序,如果你定义了相同的名称,你最终会得到ConflictingBeanDefinitionException spring 将不允许你有@Component@Bean 具有相同的名称.在 xml 中,您可以管理覆盖顺序,这就是您可以通过 xml 执行此操作的原因。在注释中你不能这样做。

    任何给定的 Spring 上下文对于任何给定的 id 或名称只能有一个 bean。对于 XML id 属性,这是由模式验证强制执行的。在 name 属性的情况下,这是由 Spring 的逻辑强制执行的。

    但是,如果一个上下文是由两个不同的 XML 描述符文件构成的,并且两个文件都使用一个 id,那么其中一个将“覆盖”另一个。确切的行为取决于文件在上下文加载时的顺序。

    所以虽然有可能,但不建议这样做。它容易出错且脆弱,如果您更改其中一个而不是另一个的 ID,您将无法从 Spring 获得任何帮助。

    但是,如果一个上下文是由两个不同的 XML 描述符文件构成的,并且两个文件都使用一个 id,那么其中一个将“覆盖”另一个。确切的行为取决于文件在上下文加载时的顺序。

    【讨论】:

    • 没错,Primary 在您上面显示的情况下有效(基于类型的注入)。但是在我的情况下,我经常有多个基于名称注入的某种类型的实例。但是@Primary 仍然不允许定义两个同名的bean。
    • 我怀疑你正在尝试做一些春天注定不会做的事情。我的建议是使用@Primary,如果您需要另一个bean,请使用@Qualifier
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2017-02-18
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多