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 {
//...
}