Spring Аннотации Autowire с несколькими интерфейсами

Предположим, что у вас есть один интерфейс

public interface A {
  public void doSomething();
}

и два класса реализации

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

}

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

}

И, наконец, класс, который будет использовать реализацию "A":

@Component
public class MyClass {
  @Autowire
  A a;
}

Теперь, если я хочу добавить AImpl1, я добавляю @Qualifier ( "aImpl1" ), а если я хочу добавить AImpl2, я добавляю @Qualifier ( "aImpl2" )

Вопрос: Можно ли как-то проинструктировать spring все реализации "A" в этом случае AImpl1 и AImpl2 и использовать некоторые специальные приложения для выбора наиболее подходящей реализации? например, в этом случае моя конвенция может использовать реализацию с наибольшим суффиксом (т.е. AImpl2)?

EDIT: класс MyClass вообще не должен знать о логике поиска реализации, он должен просто найти свое свойство "a" с объектом AImpl2.

Ответ 1

Предполагая, что у вас уже есть сотни интерфейсов и реализаций (как вы сказали в комментарии), и вы не хотите реорганизовывать весь код... тогда это сложная проблема... и это сложное решение:

Вы можете создать пользовательский BeanDefinitionRegistryPostProcessor и реализовать либо метод postProcessBeanDefinitionRegistry, либо postProcessBeanFactory.

Таким образом, у вас есть доступ ко всем определениям 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 say is this one

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

    }



}

Жесткая часть - найти имя bean, это зависит от специфики вашего приложения. Я предполагаю, что использование согласованного соглашения об именах поможет.

Update:

Кажется, что оба метода в интерфейсе BeanDefinitionRegistryPostProcessor могут использоваться для этой цели. Имея в виду, что в фазе postProcessBeanDefinitionRegistry beans, сконфигурированный с помощью классов @configuration, пока недоступен, как отмечено в комментариях ниже.

С другой стороны, они действительно доступны в postProcessBeanFactory.

Ответ 2

Вы можете вводить все имплантации как List:

@Autowired
List<A> as;

или как Map с именем bean в качестве ключа:

@Autowired
Map<String, A> as; 

а затем выберите правильную реализацию вручную (возможно, в методе setter):

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

Ответ 3

Если у вас есть класс конфигурации, вы можете использовать метод, чтобы принять решение о том, какая реализация A вернется. Затем автоматически добавит соответствующий экземпляр для этого класса.

@Configuration
public class ApplicationConfiguration {

    @Bean
    A getA() {
        // instantiate the implementation of A that you would like to have injected
        // or you could use reflection to find the correct class from the classpath.
        // return the instance
    }
}

Это предполагает, что вы всегда хотите использовать один и тот же экземпляр везде, где вы впрыскиваете A. Если нет, тогда у вас могут быть разные @@w810 аннотированные методы с именами для получения разных версий.