【问题标题】:How to specify which subclass Spring should use如何指定 Spring 应该使用哪个子类
【发布时间】:2026-02-11 19:45:02
【问题描述】:

在我基于 spring 的项目中,我有一个带有类的核心模块('core')

@Component
public class Superclass {
    // stuff
}

在整个代码中按类型注入的实例如下:

public class AService {

    @Autowired
    private Superclass superclass;

    // service stuff
}

我还有两个依赖于核心模块的模块,其中一个(我们称之为“module1”)扩展了超类

@component
public class Subclass extends Superclass {
    // overridden stuff
}

另一个模块('module2')按原样使用超类

现在我希望当我编译和运行“child1”时,Subclass 的实例在任何需要 Superclass 的实例的地方使用。于是我写了一个配置类:

@Configuration
public class Module2Configuration {

    @Bean
    public Superclass superclass(){
        return new Subclass();
    }
}

当我运行它时,我看到 both Superclass Subclass 被实例化,这绝对是 not 我想要的。如何在 'module1' 中指定 Spring 应该实例化的类型?

【问题讨论】:

    标签: java spring inheritance annotations


    【解决方案1】:

    您可以使用@Qualifier("some name") 注释。 有更多相关信息:http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/

    【讨论】:

      【解决方案2】:

      如文档中所述,Spring 急切地实例化单例 bean:

      默认情况下,ApplicationContext 实现会在初始化过程中急切地创建和配置所有单例 bean。

      这或许可以解释为什么会同时创建 @Components

      要指定作为依赖项提供的实现,您可能需要检查Qualifiers,以便在不同的实现之间进行选择。结合延迟加载,这应该可以解决问题。

      根据您的个人喜好,您还可以使用委托而不是使用分离接口的继承:

      public interface MyService {
          public String foobar(int baz);
      }
      
      public static class CommonBehavior {
          // whatever is used by Superclass and Subclass
      }
      
      @Component @Lazy
      public class FormerSuperClass implements MyService {
         private final CommonBehavior ...;
         ...
      }
      
      @Component @Lazy
      public class FormerSubClass implements MyService {
         private final CommonBehavior ...;
         ...
      }
      

      祝你好运!

      【讨论】:

      • 谢谢,我想到了,但是'core'模块对'module1的子类一无所知,我想在'core'代码期望的任何地方使用它超类。我想不出,我应该如何限定 AService 的字段,这样它就会比没有限定符知道更多。或者我应该以某种方式限定子类?或两者?你能详细说明一下吗?
      • 嘿,我不确定我的应用程序结构和意图是否正确,所以请原谅 :-)。两种实现都必须在同一个应用程序/应用程序上下文中处于活动状态吗?也许您可以删除 @Component 注释,因为使用 @Bean 无论如何您正在创建一个新实例?我通常的策略是创建一个单独的接口(来自 SuperClass),将其放入“核心”并分别创建所需的实现(可能在模块 1 和模块 2 中)。我希望我能更接近您的需求...
      • 我想我会按照你的建议坚持核心中的单独接口和模块中的实现。但最初的想法是“核心”模块将是一个成熟的应用程序,具有自己的 spring 配置,不知道其他模块,并且“模块 1”将扩展核心的 bean 之一(超类 ) 稍微改变它的行为(在 Subclass 中),然后告诉 spring 使用它,而不是创建一个稍微不同的应用程序版本。我相信我没有从问题中说清楚。我的错。
      • 我想给你更多的提示,但是如果没有更多的上下文很难判断其他选项是否更合适。如果您可以再投入一个小时,请查看 Spring 文档。它有很多小例子。
      【解决方案3】:

      有两种方法:使用@Qualifier("SubclassName") 或将您的子类标记为@Component,并在@Autowired 时声明子类

      在你的情况下:

      1. 使用@Qualifier("SubclassName")

        @Component
        public class Superclass {
            // stuff
        }
        
        @component
        public class Subclass extends Superclass {
            // overridden stuff
        }
        
        public class AService {
        
            @Autowired
            @Qualifier("Subclass")
            private Superclass superclass;
        
            // service stuff
        }
        

      2.将你的子类标记为@Component,并在@Autowired时声明子类

          public class Superclass {
              // stuff
          }
      
          @component
          public class Subclass extends Superclass {
              // overridden stuff
          }
      
          public class AService {
      
              @Autowired
              private Subclass subclass;
      
              // service stuff
          }
      

      【讨论】: