Проверка компонентов для пользовательской аннотации по интерфейсу

У меня есть конфигурация сканирования компонентов как это:

   @Configuration
   @ComponentScan(basePackageClasses = {ITest.class},
                  includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = JdbiRepository.class)})
   public class MyConfig {

   }

В принципе, я хотел бы создать интерфейс сканирования, который имеет JdbiRepository аннотацию

@JdbiRepository
public interface ITest {
  Integer deleteUserSession(String id);
}

И я хотел бы создать прокси-реализацию моих интерфейсов. Для этого я зарегистрировал пользовательский SmartInstantiationAwareBeanPostProcessor, который в основном создает необходимые экземпляры, но указанная выше конфигурация не проверяет интерфейсы с аннотацией JdbiRepository.

Как сканировать интерфейсы с помощью пользовательской аннотации?

Изменить:

Кажется, что org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#isCandidateComponent принимает только конкретные классы.

/**
 * Determine whether the given bean definition qualifies as candidate.
 * <p>The default implementation checks whether the class is concrete
 * (i.e. not abstract and not an interface). Can be overridden in subclasses.
 * @param beanDefinition the bean definition to check
 * @return whether the bean definition qualifies as a candidate component
 */
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
}

Edit:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface JdbiRepository {

   /**
    * The value may indicate a suggestion for a logical component name,
    * to be turned into a Spring bean in case of an autodetected component.
    * @return the suggested component name, if any
    */
   String value() default "";
}

Ответ 1

Как я уже говорил, сканирование компонентов работает только для конкретных классов.

Чтобы решить мою проблему, я выполнил следующие шаги:

  • Реализовано пользовательское org.springframework.context.annotation.ImportBeanDefinitionRegistrar
  • Создал пользовательскую аннотацию EnableJdbiRepositories, которая импортирует мой пользовательский импортер.
  • Extended ClassPathScanningCandidateComponentProvider для сканирования интерфейсов. Мой пользовательский импортер использовал этот класс для сканирования интерфейсов.

Ответ 2

Вместо сканирования аннотированного интерфейса вы можете создать фиктивную реализацию и соответственно аннотировать ее:

@JdbiRepository
public class DummyTest implements ITest {
  public Integer deleteUserSession(String id) {
    // nothing here, just being dummy
  }
}

Затем сканируйте фиктивную реализацию basePackageClasses = {DummyTest.class}.

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

Ответ 3

Создание реализации Dummy кажется довольно взломанным для меня, и все этапы Cemo требуют больших усилий. Но расширение ClassPathScanningCandidateComponentProvider является самым быстрым способом:

ClassPathScanningCandidateComponentProvider scanningProvider = new ClassPathScanningCandidateComponentProvider(false) {
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return true;
    }
};

Теперь вы также можете сканировать интерфейсы с (пользовательскими) аннотациями с помощью Spring - , который также работает в Spring средах с загрузочным салоном, где fast-classpath-scanner (что упоминается в поэтому q & a) может иметь некоторые ограничения.