Рубрики
Без рубрики

Spring @ComponentScan – Типы фильтров

Изучите различные типы параметров фильтра, доступных с помощью аннотации @ComponentScan.

Автор оригинала: baeldung.

1. Обзор

В предыдущем уроке мы узнали об основах сканирования компонентов Spring .

В этой записи мы увидим различные типы параметров фильтра, доступных с помощью @ComponentScan |/аннотации .

2. Фильтр @ComponentScan

По умолчанию классы с аннотациями @Component, @Repository, @Service, @Controller регистрируются как Spring beans . То же самое касается классов, аннотированных пользовательской аннотацией, которая аннотируется с помощью @Component . Мы можем расширить это поведение с помощью include Filters и | exclude Filters параметров аннотации @ComponentScan .

Существует пять типов фильтров, доступных для Существует пять типов фильтров, доступных для :

  • АННОТАЦИЯ
  • ASSIGNABLE_TYPE
  • ASPECTJ
  • РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ
  • ТРАДИЦИЯ

Мы подробно рассмотрим их в следующих разделах.

Следует отметить, что все эти фильтры могут включать или исключать классы из сканирования. Для простоты в наших примерах мы будем включать только классы.

3. Тип фильтра.АННОТАЦИЯ

То АННОТАЦИЯ тип фильтра включает или исключает классы в сканировании компонентов, которые помечены заданными аннотациями.

Допустим, например, что у нас есть аннотация @Anima l:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Animal { }

Теперь давайте определим класс Elephant , который использует @Animal :

@Animal
public class Elephant { }

Наконец, давайте использовать тип фильтра .АННОТАЦИЯ чтобы указать Spring для сканирования @Animal -аннотированные классы:

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
        classes = Animal.class))
public class ComponentScanAnnotationFilterApp { }

Как мы видим, сканер улавливает наш Слон просто отлично:

@Test
public void whenAnnotationFilterIsUsed_thenComponentScanShouldRegisterBeanAnnotatedWithAnimalAnootation() {
    ApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(ComponentScanAnnotationFilterApp.class);
    List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
            .filter(bean -> !bean.contains("org.springframework")
                    && !bean.contains("componentScanAnnotationFilterApp"))
            .collect(Collectors.toList());
    assertThat(beans.size(), equalTo(1));
    assertThat(beans.get(0), equalTo("elephant"));
}

4. Тип фильтра.ASSIGNABLE_TYPE

То ASSIGNABLE_TYPE фильтры всех классов во время компонентов могут либо расширять класс, либо реализовывать интерфейс указанного типа.

Во-первых, давайте объявим интерфейс Animal :

public interface Animal { }

И снова, давайте объявим наш Elephant класс, на этот раз реализующий Животное интерфейс :

public class Elephant implements Animal { }

И снова, давайте объявим наш Elephant класс, на этот раз реализующий Животное

public class Cat implements Animal { }

Теперь давайте использовать ASSIGNABLE_TYPE , чтобы направить Spring на поиск Animal -реализующих классов:

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
        classes = Animal.class))
public class ComponentScanAssignableTypeFilterApp { }

И мы увидим, что и Кошка , и Слон будут отсканированы:

@Test
public void whenAssignableTypeFilterIsUsed_thenComponentScanShouldRegisterBean() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanAssignableTypeFilterApp.class);
    List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
      .filter(bean -> !bean.contains("org.springframework")
        && !bean.contains("componentScanAssignableTypeFilterApp"))
      .collect(Collectors.toList());
    assertThat(beans.size(), equalTo(2));
    assertThat(beans.contains("cat"), equalTo(true));
    assertThat(beans.contains("elephant"), equalTo(true));
}

5. Тип фильтра.РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ

То РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ фильтр проверяет, соответствует ли имя класса заданному шаблону регулярного выражения. фильтр проверяет, соответствует ли имя класса заданному шаблону регулярного выражения. проверяет как простые, так и полные имена классов.

Еще раз давайте объявим наш класс Elephant . На этот раз не реализован какой-либо интерфейс или аннотирован какой-либо аннотацией :

public class Elephant { }

Давайте объявим еще один класс Cat :

public class Cat { }

Теперь давайте объявим Loin класс:

public class Loin { }

Давайте использовать Тип фильтра . РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ , которое предписывает Spring сканировать классы, соответствующие регулярному выражению .*[nt]. Наше выражение регулярного выражения оценивает все, что содержит nt:

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.REGEX,
        pattern = ".*[nt]"))
public class ComponentScanRegexFilterApp { }

На этот раз в нашем тесте мы увидим, что весна сканирует Слона , но не Льва :

@Test
public void whenRegexFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingRegex() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanRegexFilterApp.class);
    List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
      .filter(bean -> !bean.contains("org.springframework")
        && !bean.contains("componentScanRegexFilterApp"))
      .collect(Collectors.toList());
    assertThat(beans.size(), equalTo(1));
    assertThat(beans.contains("elephant"), equalTo(true));
}

6. Тип фильтра.ASPECTJ

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

В этом случае мы можем повторно использовать те же три класса, что и в предыдущем разделе.

Давайте использовать тип фильтра .ASPECTJ для направления Spring на сканирование классов, соответствующих нашему выражению AspectJ :

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ,
  pattern = "com.baeldung.componentscan.filter.aspectj.* "
  + "&& !(com.baeldung.componentscan.filter.aspectj.L* "
  + "|| com.baeldung.componentscan.filter.aspectj.C*)"))
public class ComponentScanAspectJFilterApp { }

Хотя это немного сложно, наша логика здесь хочет, чтобы бобы, которые начинаются ни с “L”, ни с “C” в имени класса, так что у нас снова остается Elephant s:

@Test
public void whenAspectJFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingAspectJCreteria() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanAspectJFilterApp.class);
    List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
      .filter(bean -> !bean.contains("org.springframework")
        && !bean.contains("componentScanAspectJFilterApp"))
      .collect(Collectors.toList());
    assertThat(beans.size(), equalTo(1));
    assertThat(beans.get(0), equalTo("elephant"));
}

7. Тип фильтра.ТРАДИЦИЯ

Если ни один из вышеперечисленных типов фильтров не соответствует нашим требованиям, то мы также можем создать пользовательский тип фильтра. Например, предположим, что мы хотим сканировать только классы, имя которых состоит из пяти символов или короче.

Чтобы создать пользовательский фильтр, нам нужно реализовать фильтр org.springframework.core.type.filter.Тип фильтра :

public class ComponentScanCustomFilter implements TypeFilter {

    @Override
    public boolean match(MetadataReader metadataReader,
      MetadataReaderFactory metadataReaderFactory) throws IOException {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String fullyQualifiedName = classMetadata.getClassName();
        String className = fullyQualifiedName.substring(fullyQualifiedName.lastIndexOf(".") + 1);
        return className.length() > 5 ? true : false;
    }
}

Давайте использовать Тип фильтра . CUSTOM который передает Spring для сканирования классов с помощью нашего пользовательского фильтра Компоненты могут выполнять пользовательский фильтр:

@Configuration
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM,
  classes = ComponentScanCustomFilter.class))
public class ComponentScanCustomFilterApp { }

Теперь пришло время посмотреть тестовый случай нашего пользовательского фильтра Компоненты могут фильтровать пользовательские фильтры:

@Test
public void whenCustomFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingCustomFilter() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanCustomFilterApp.class);
    List beans = Arrays.stream(applicationContext.getBeanDefinitionNames())
      .filter(bean -> !bean.contains("org.springframework")
        && !bean.contains("componentScanCustomFilterApp")
        && !bean.contains("componentScanCustomFilter"))
      .collect(Collectors.toList());
    assertThat(beans.size(), equalTo(1));
    assertThat(beans.get(0), equalTo("elephant"));
}

8. Резюме

В этом уроке мы представили фильтры, связанные с @ComponentScan.

Как обычно, полный код доступен на GitHub .