Весна зависит от качества бобов - PullRequest
0 голосов
/ 13 марта 2020

Как я могу использовать @ConditionalOnBean с квалификаторами в Spring?

В следующем автономном примере: у меня

  • интерфейс службы SomeService
  • интерфейс адаптера SomeAdapter
  • a GreenService реализация SomeService с квалификатором @Green, в зависимости от SomeAdapter с квалификатором @Green
  • BlueService реализация SomeService с квалификатором @Blue, в зависимости от SomeAdapter с квалификатором @Blue
  • необязательная GreenAdapter реализация SomeAdapter с квалификатором @Green
  • необязательная BlueAdapter реализация SomeAdapter с квалификатором @Blue

@ Зеленый квалификатор:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Green { }

@ Синий квалификатор:

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Blue {  }

GreenService:

@Green
@Service
@ConditionalOnBean(value = SomeAdapter.class, annotation = Green.class)
public class GreenService implements SomeService {

    @Autowired
    @Green
    private SomeAdapter adapter;
}

BlueService:

@Blue
@Service
@ConditionalOnBean(value = SomeAdapter.class, annotation = Blue.class)
public class BlueService implements SomeService {

    @Autowired
    @Blue
    private SomeAdapter adapter;
}

GreenAdapter:

@Green
@Component
public class GreenAdapter implements SomeAdapter {}

BlueAdapter:

@Blue
@Component
public class BlueAdapter implements SomeAdapter {}

Тест чтобы проверить активацию бина (не содержит BlueAdapter, поэтому BlueService не будет активен):

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {GreenService.class, BlueService.class, GreenAdapter.class})
public class GreenBlueServiceTest {

    @Autowired
    @Green
    private Optional<SomeService> greenService;

    @Autowired
    @Blue
    private Optional<SomeService> blueService;

    @Test
    public void testGreen() {
        assertTrue(greenService.isPresent());
    }

    @Test
    public void testBlue() {
        assertFalse(blueService.isPresent());
    }
}

Проблема : тест выигран ' бегать, сообщая отсутствует зависимость (SomeAdapter с квалификатором @Blue для BlueService). @ConditionalOnBean должен отключить bean-компонент, поскольку SomeAdapter с квалификатором @Blue отсутствует, но это не сработало.

Я обнаружил, что при добавлении аннотации @TrueBlue (аналогично * 1078) *, но не помечен как @Annotation) для BlueAdapter, и используйте эту аннотацию для активации bean-компонента на BlueService, он работает так, как должен (тестируйте все зеленым).

В заключение:

  • условная активация bean с необходимыми аннотациями работает (в принципе)
  • она не работает, однако, когда требуется аннотация @Qualifier

Is это ошибка, или по дизайну, и как мне добиться такой условной активации, которая зависит от квалифицированного бина в Spring ?


РЕДАКТИРОВАТЬ: ответ @ bruno-leite объясняет, почему он не работает (аннотация и тип бина могут совпадать на разных бинах), но остается вопрос:

Как вы можете условно активировать бин, если другой бин данного типа И данная аннотация (или спецификатор c) ESENT

1 Ответ

1 голос
/ 13 марта 2020

Обратите внимание, что в документации @ ConditionalOnBean написано:

All the requirements must be met for the condition to match, but they do not have to be met by the same bean. ` 

Обратите внимание на часть, в которой написано but they do not have to be met by the same bean.


Условие ниже будет совпадать, если есть какой-либо компонент типа SomeAdapter плюс любой компонент , аннотированный @Blue

@ConditionalOnBean(value = SomeAdapter.class, annotation = Blue.class)

Итак, у вас есть компонент BlueService, аннотированный @Blue и у вас также есть GreenAdapter, то есть SomeAdapter.class условие проходит. Это заставляет нас думать, что это будет соответствовать только SomeAdapter с аннотацией @Blue.

Чтобы ваш пример работал, просто удалите аннотацию @Blue из BlueService


Взгляните на getMatchingBeans метод OnBeanCondition класса. Вы увидите, что условия оцениваются отдельно.

...