1. 程式人生 > 實用技巧 >component-scan 標籤的 use-default-filters 屬性用法

component-scan 標籤的 use-default-filters 屬性用法

在進行 SSM 整合時,常常使用<component-scan>標籤進行註解掃描,而該標籤中有個常常被忽略的屬性 use-default-filters。該屬性是個特別重要的屬性,本文將會對該屬性進行介紹。

原理分析

在進行 SSM 整合時,一般都會將 Spring 和 SpringMVC 的配置分別寫在兩個配置檔案中。Spring 配置檔案一般配置的是非 Web 元件的 bean,比如 DataSource、Service;而 SpringMVC 配置檔案一般配置的是 Web 元件的 bean,比如控制器、檢視解析器。所以,Spring 和 SpringMVC 配置檔案的註解掃描的包路徑是不同的。

☕️ Spring 配置檔案中的註解掃描

<!-- 配置 IoC 容器註解掃描的包路徑 -->
<context:component-scan base-package="com.example">
    <!-- 制定掃包規則,不掃描 @Controller 註解修飾的 Java 類,其它還是要掃描 -->
    <context:exclude-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

☕️ SpringMVC 配置檔案中的註解掃描

<!-- 配置 IoC 容器的註解掃描的包路徑 -->
<context:component-scan base-package="com.example" use-default-filters="false">
    <!-- 制定掃包規則,只掃描使用 @Controller 註解修飾的 Java 類 -->
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

從上面可以發現,使用<exclude-filter>標籤時,沒有將 use-default-filters 屬性設定為 false;而在使用<include-filter>標籤時,將use-default-filters屬性設定為 false。這是為什麼?

這一切都要歸結為 use-default-filters 屬性的作用,該屬性的預設值為 true,意為使用預設的 Filter 進行註解掃描,而該 Filter 會掃描所有 @Component 註解及其子註解。我們檢視原始碼:

protected void registerDefaultFilters() {
    // 將 @Component 註解新增進 Filter 掃描中
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

    try {
        this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
        this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    } catch (ClassNotFoundException var4) {
    }

    try {
        this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
        this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    } catch (ClassNotFoundException var3) {
    }
}

因此預設的 filter 會掃描所有 @Component 註解修飾的 Java 類,而 @Controller、@Service、@Repository 甚至是 @Configuration 註解都是 @Componet 的衍生註解,所以也會被掃描到。因此,最簡單的註解掃描配置就是隻配置包路徑,而 use-default-filters 屬性不需要配置,其值預設為 true:

<!-- 配置 IoC 容器的註解掃描的包路徑 -->
<context:component-scan base-package="com.example"/>

⭐️ 現在回過頭檢視 Spring 配置檔案中的配置:

<!-- 配置 IoC 容器的註解掃描的包路徑 -->
<context:component-scan base-package="com.example">
    <!-- 制定掃包規則,不掃描 @Controller 註解修飾的 Java 類,其它還是要掃描 -->
    <context:exclude-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

use-default-filters 預設值為 true,預設會掃描 @Component、@Controller、@Service、@Repository 甚至是 @Configuration 註解修飾的 Java 類;而<exclude-filter>標籤指定將 @Controller 註解排除,所以最後只會掃描 @Component、@Service、@Repository 和 @Configuration 註解修飾的 Java 類。

⭐️ 檢視 SpringMVC 配置檔案中的配置

<!-- 配置 IoC 容器的註解掃描的包路徑 -->
<context:component-scan base-package="com.example" use-default-filters="false">
    <!-- 制定掃包規則,只掃描使用 @Controller 註解修飾的 Java 類 -->
    <context:include-filter type="annotation"
                            expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

use-default-filters 屬性值設定為 false,預設的 filters 關閉,意味著不會進行任何掃描;而<include-filter>標籤指定掃描 @Controller 註解,所以最終只會掃描 @Controller 註解修飾的 Java 類。


註解方式使用

✏️ Spring 配置類中的註解掃描配置

@Configuration
@ComponentScan(value = "com.example",  // 配置 IoC 容器註解掃描的包路徑
        // 制定掃包規則,不掃描 @Controller 註解修飾的 Java 類,其它還是要掃描
        excludeFilters = @Filter(type = FilterType.ANNOTATION, 
                                 value = Controller.class))
public class SpringConfig {
    //...
}

✏️ SpringMVC 配置類中的註解掃描配置

@Configuration
@ComponentScan(value = "com.example",  // 配置 IoC 容器註解掃描的包路徑
        useDefaultFilters = false,     // 關閉預設的註解掃描的 Filter
        // 制定掃包規則,只掃描使用 @Controller 註解修飾的 Java 類
        includeFilters = @Filter(type = FilterType.ANNOTATION, 
                                 value = Controller.class)
)
public class SpringMvcConfig {
	//...
}