具有多个接口实现的Spring Autowire注释

Oma*_*bji 11 java spring

假设您有一个界面

public interface A {
  public void doSomething();
}
Run Code Online (Sandbox Code Playgroud)

和两个实现类

@Component(value="aImpl1")
public class AImpl1 implements A {

}

@Component(value="aImpl2")
public class AImpl2 implements A{

}
Run Code Online (Sandbox Code Playgroud)

最后一个将使用"A"实现的类:

@Component
public class MyClass {
  @Autowire
  A a;
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我想注入AImpl1,我添加@Qualifier("aImpl1"),而如果我想注入AImpl2,我添加@Qualifier("aImpl2")

问题是:是否有可能以某种方式指示spring查找"A"的所有实现,在这种情况下是AImpl1AImpl2,并使用一些特定于应用程序的约定来选择最合适的实现?例如,在这种情况下,我的约定可以使用具有最大后缀的实现(即AImpl2)?

编辑:类MyClass根本不应该知道实现查找逻辑,它应该只找到它的属性"a"设置与AImpl2的对象.

axt*_*avt 11

您可以将所有实现注入List:

@Autowired
List<A> as;
Run Code Online (Sandbox Code Playgroud)

或者将Mapbean名称作为键:

@Autowired
Map<String, A> as; 
Run Code Online (Sandbox Code Playgroud)

然后手动选择正确的实现(也许,在setter方法中):

@Autowired
public void setAs(Map<String, A> as) {
    this.a = ...;
}
Run Code Online (Sandbox Code Playgroud)


gar*_*rst 5

假设你已经拥有数百个接口和实现(正如你在评论中所说的那样),并且你不想重构所有代码......那么这是一个棘手的问题......这是一个棘手的解决方案:

您可以创建自定义BeanDefinitionRegistryPostProcessor并实现方法postProcessBeanDefinitionRegistrypostProcessBeanFactory.

这样,您可以在实例化和注入之前访问所有 bean定义.您的逻辑是为了找到每个接口的首选实现,然后将其设置为主要接口.

@Component
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(
            BeanDefinitionRegistry registry) throws BeansException {

          // this method can be used to set a primary bean, although 
          // beans defined in a @Configuration class will not be avalable here.

    }

    @Override
    public void postProcessBeanFactory(
            ConfigurableListableBeanFactory beanFactory) throws BeansException {     

        // here, all beans are available including those defined by @configuration, @component, xml, etc.

        // do some magic to somehow find which is the preferred bean name for each interface 
        // you have access to all bean-definition names with: beanFactory.getBeanDefinitionNames()
        String beanName = "aImpl2"; // let's say is this one

        // get the definition for that bean and set it as primary
        beanFactory.getBeanDefinition(beanName).setPrimary(true)

    }



}
Run Code Online (Sandbox Code Playgroud)

困难的部分是找到bean名称,它取决于您的应用程序的细节.我想拥有一致的命名约定会有所帮助.

更新:

似乎界面中的两种方法BeanDefinitionRegistryPostProcessor都可用于此目的.请记住,在此postProcessBeanDefinitionRegistry 阶段,通过@configuration类配置的bean尚不可用,如下面的注释中所述.

另一方面,它们确实可用postProcessBeanFactory.

  • @Jonathan,你说得对... BeanDefinitionRegistry不包含@Configuration类中定义的bean(虽然它确实包含@ Component,@ Service等注释bean).但它们在另一种方法中可用:`postProcessBeanFactory`,通过`ConfigurableListableBeanFactory`.我刚做了一个快速测试,它的确有效.我会在答案中加上这个. (2认同)