知識庫 / Spring RSS 訂閱

Spring @ComponentScan – 掃描組件過濾類型

Spring
HongKong
6
01:08 PM · Dec 06 ,2025

1. 概述

在之前的教程中,我們學習了 Spring 組件掃描的基礎知識。

在這篇文檔中,我們將瞭解帶有 <em><a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html">@ComponentScan</a> </em> 標註的不同類型的過濾器選項。

2. @ComponentScan 過濾器

默認情況下,帶有 <em/>@Component</em/>、<em/>@Repository</em/>、<em/>@Service</em/>、<em/>@Controller</em/> 註解的類會被註冊為 Spring Bean。同樣,帶有自定義註解,且該自定義註解被註解為@Component</em/> 的類也會遵循此規則。我們可以通過使用 <em/>@ComponentScan</em/> 註解的includeFilters</em/> 和 `excludeFilters</em/> 參數來擴展此行為。

`ComponentScan.Filter</em/> 提供了五種類型的過濾器:

  • ANNOTATION</em/> (註解)
  • ASSIGNABLE_TYPE</em/> (可賦值類型)
  • ASPECTJ</em/> (AspectJ)
  • REGEX</em/> (正則表達式)
  • CUSTOM</em/> (自定義)

我們將會在下一部分中詳細介紹這些過濾器。

請注意,所有這些過濾器都可以包含或排除掃描的類。為了簡化示例,我們只會在示例中包含類。

3.FilterType.ANNOTATION

“ANNOTATION” 過濾器類型包括或排除在給定註解標記的組件掃描中的類。

例如,我們有一個 @Anima 標註:

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

現在,讓我們定義一個 Elephant 類,它使用 @Animal 屬性:

@Animal
public class Elephant { }

最後,我們使用 FilterType.ANNOTATION 來告知 Spring 掃描帶有 @Animal 註解的類:

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

正如我們所見,掃描儀能夠完美地捕捉到我們 Elephant

@Test
public void whenAnnotationFilterIsUsed_thenComponentScanShouldRegisterBeanAnnotatedWithAnimalAnootation() {
    ApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(ComponentScanAnnotationFilterApp.class);
    List<String> 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 類,這次實現 Animal 接口:

public class Elephant implements Animal { }

讓我們聲明我們的 Cat 類,該類同時實現 Animal 接口:

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<String> 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.FilterType.REGEX

The&nbsp;REGEXfilter checks if the class name matching a given regex pattern. FilterType.REGEX checks both simple and fully-qualified class names.

Once again, let’s declare our Elephant class. This time not implementing any interface or annotated with any annotation:

public class Elephant { }

讓我們聲明一個額外的類 Cat

public class Cat { }

現在,讓我們聲明 Lion 類:

public class Lion { }

讓我們使用 <em>FilterType</em>.<em>REGEX</em>,它指示 Spring 掃描與正則表達式 <em>.*[nt]. </em> 匹配的類。我們的正則表達式表達式會評估所有包含 <em>nt:</em> 的內容。

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

這次測試中,我們將看到 Spring 會掃描 Elephant,但不會掃描 Lion:Lion

@Test
public void whenRegexFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingRegex() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanRegexFilterApp.class);
    List<String> 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.FilterType.ASPECTJ

當我們需要使用表達式來選擇複雜類集時,我們需要使用FilterType ASPECTJ

對於這個用例,我們可以重用前一節中相同的三個類。

讓我們使用FilterType.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”開頭的豆子,這使得我們再次得到 類:

@Test
public void whenAspectJFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingAspectJCreteria() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanAspectJFilterApp.class);
    List<String> 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. FilterType.CUSTOM

如果以上任何過濾類型均不符合我們的要求,我們還可以創建自定義過濾類型。例如,假設我們只想掃描名稱不超過五個字符的類。

要創建自定義過濾,我們需要實現 org.springframework.core.type.filter.TypeFilter:

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;
    }
}

讓我們使用 FilterType.CUSTOM,它指示 Spring 使用我們的自定義過濾器 ComponentScanCustomFilter 來掃描類:

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

現在是時候查看我們自定義過濾器 ComponentScanCustomFilter 的測試用例。

@Test
public void whenCustomFilterIsUsed_thenComponentScanShouldRegisterBeanMatchingCustomFilter() {
    ApplicationContext applicationContext =
      new AnnotationConfigApplicationContext(ComponentScanCustomFilterApp.class);
    List<String> 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 相關的過濾器。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.