1. 概述
本教程將介紹 Spring 中的組件掃描。 在使用 Spring 時,我們可以對類進行註解,將其轉換為 Spring Bean。 此外,我們可以告訴 Spring 在哪裏搜索這些註解類,並非所有類都需要成為該運行時的 Bean。
當然,組件掃描有一些默認設置,但我們也可以自定義搜索包。
首先,讓我們看看默認設置。
2. <em @ComponentScan> 無參數配置
2.1. 使用 @ComponentScan 在 Spring 應用中
使用 Spring 時,我們使用 @ComponentScan 註解以及 @Configuration 註解來指定我們想要掃描的包。 @ComponentScan 沒有參數時,它會告訴 Spring 掃描當前包及其所有子包。
假設我們有以下 @Configuration 在 com.baeldung.componentscan.springapp 包中:
@Configuration
@ComponentScan
public class SpringComponentScanApp {
private static ApplicationContext applicationContext;
@Bean
public ExampleBean exampleBean() {
return new ExampleBean();
}
public static void main(String[] args) {
applicationContext =
new AnnotationConfigApplicationContext(SpringComponentScanApp.class);
for (String beanName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanName);
}
}
}此外,我們還擁有 Cat 和 Dog 組件,位於 com.baeldung.componentscan.springapp.animals 包中:
package com.baeldung.componentscan.springapp.animals;
// ...
@Component
public class Cat {}package com.baeldung.componentscan.springapp.animals;
// ...
@Component
public class Dog {}最後,我們有 Rose 組件,位於 com.baeldung.componentscan.springapp.flowers 包中:
package com.baeldung.componentscan.springapp.flowers;
// ...
@Component
public class Rose {}<em>main()</em> 方法的輸出將包含 <em>com.baeldung.componentscan.springapp</em> 包及其子包的所有 Bean:
springComponentScanApp
cat
dog
rose
exampleBean請注意,主應用程序類也是一個 Bean,因為它被標記為 ,這本身就是一個 。
我們還應該注意的是,主應用程序類和配置類不一定相同。如果它們不同,我們不必在意主應用程序類放在哪裏。 只有配置類的位置重要,因為默認情況下組件掃描從其包開始。
最後,請注意,在我們的示例中, 等效於:
@ComponentScan(basePackages = "com.baeldung.componentscan.springapp")basePackages參數是一個包或包的數組,用於掃描。
2.2. 在 Spring Boot 應用中使用 @ComponentScan
Spring Boot 的訣竅在於許多事情會自動發生。我們使用 @SpringBootApplication> 標註,但它實際上是三個標註的組合:
@Configuration
@EnableAutoConfiguration
@ComponentScan讓我們在 com.baeldung.componentscan.springbootapp 包中創建類似的結構。 這一次,主應用程序將是:
package com.baeldung.componentscan.springbootapp;
// ...
@SpringBootApplication
public class SpringBootComponentScanApp {
private static ApplicationContext applicationContext;
@Bean
public ExampleBean exampleBean() {
return new ExampleBean();
}
public static void main(String[] args) {
applicationContext = SpringApplication.run(SpringBootComponentScanApp.class, args);
checkBeansPresence(
"cat", "dog", "rose", "exampleBean", "springBootComponentScanApp");
}
private static void checkBeansPresence(String... beans) {
for (String beanName : beans) {
System.out.println("Is " + beanName + " in ApplicationContext: " +
applicationContext.containsBean(beanName));
}
}
}所有其他包和類保持不變,我們只需將它們複製到附近的 com.baeldung.componentscan.springbootapp 包中。
Spring Boot 掃描包的方式與我們之前的示例類似。 讓我們查看輸出:
Is cat in ApplicationContext: true
Is dog in ApplicationContext: true
Is rose in ApplicationContext: true
Is exampleBean in ApplicationContext: true
Is springBootComponentScanApp in ApplicationContext: true我們之所以在第二個示例中僅檢查 Bean 的存在(而不是打印出所有 Bean),是因為輸出結果會過於龐大。
這是因為隱式的 @EnableAutoConfiguration 註解,導致 Spring Boot 自動創建了大量的 Bean,並依賴於 pom.xml 文件中的依賴項。
3. 使用 @ComponentScan 帶有參數
現在,讓我們自定義掃描路徑。例如,假設我們想要排除 Rose Bean。
3.1. 使用 @ComponentScan 指定特定包
我們可以通過多種方式實現這一點。首先,我們可以更改基礎包:
@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals")
@Configuration
public class SpringComponentScanApp {
// ...
}現在輸出將會是:
springComponentScanApp
cat
dog
exampleBean讓我們來看看背後的內容:
- springComponentScanApp 被創建,因為它是一個作為參數傳遞給 AnnotationConfigApplicationContext 的配置。
- exampleBean 是在配置中配置的 Bean。
- cat 和 dog 位於指定的 com.baeldung.componentscan.springapp.animals 包中。
以上所有自定義選項在 Spring Boot 中同樣適用。我們可以結合使用 @ComponentScan 與 @SpringBootApplication,結果將相同:
@SpringBootApplication
@ComponentScan(basePackages = "com.baeldung.componentscan.springbootapp.animals")3.2. 使用 @ComponentScan 指定多個包
Spring 提供了一種便捷的方式來指定多個包名。 要做到這一點,我們需要使用字符串數組。
數組中的每個字符串都表示一個包名:
@ComponentScan(basePackages = {"com.baeldung.componentscan.springapp.animals", "com.baeldung.componentscan.springapp.flowers"})當然,以下是翻譯後的內容:
或者,自 Spring 4.1.1 版本起,我們可以使用逗號、分號或空格來分隔包列表:
@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals;com.baeldung.componentscan.springapp.flowers")
@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals,com.baeldung.componentscan.springapp.flowers")
@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals com.baeldung.componentscan.springapp.flowers")3.3. 使用 @ComponentScan 排除指定類
另一種方法是使用過濾器,指定要排除的類的模式:
@ComponentScan(excludeFilters =
@ComponentScan.Filter(type=FilterType.REGEX,
pattern="com\\.baeldung\\.componentscan\\.springapp\\.flowers\\..*"))我們還可以選擇不同的過濾類型,因為該標註支持多種靈活的選項,用於過濾掃描的類:
@ComponentScan(excludeFilters =
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Rose.class))4. 默認包
我們應該避免將 <em >@Configuration</em> 類放在默認包中(即不指定包名)。如果這樣做,Spring 會掃描 classpath 中所有 jar 包中的所有類,這會導致錯誤,並且應用程序可能無法啓動。
5. 結論
在本文中,我們學習了 Spring 默認掃描哪些包以及如何自定義這些路徑。