在使用Spring框架開發應用的過程當中,你們都知道使用Spring開發應用程序,咱們應用程序中大多數的Bean都是經過Spring的IOC容器來管理。將Bean注入到Spring IOC容器中的方式多種多樣,如經過傳統的XML方式注入,經過註解的方式注入等。本文咱們就來詳細的探索一下在使用註解配置的方式注入Bean時,@ComponentScan註解組件掃描的應用。正則表達式
顧名思義,@ComponentScan註解提供給咱們的功能就是自動組件掃描,將指定包下的被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean自動掃描注入到Spring IOC容器中,由Spring IOC容器統一管理這些Bean。
註解中的屬性項:spring
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
在com.training.componentscan包下咱們分別建立component、controller、repository、service、config、filter包。app
在component包中建立SoftWareComponent類,加@Component註解:框架
@Component public class SoftWareComponent { //... ... }
在controller包中建立SoftWareController類,加@Controller註解:單元測試
@Controller public class SoftWareController { //... ... }
在repository包中建立SoftWareRepository類,加@Repository註解:測試
@Repository public class SoftWareRepository { //... ... }
在service包中建立SoftWareService類,加@Service註解:spa
@Service public class SoftWareService { //... ... }
在config包中建立ComponentScanConfig類,寫入以下內容:.net
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan") //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { //... ... }
咱們建立一個單元測試類IOCTest,用來測試看有哪些組件被注入到了Spring IOC容器中。code
public class IOCTest { @Test public void test() { AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(ComponentScanConfig.class); String[] names = application.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } } }
執行單元測試咱們獲得以下結果:component
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareController
softWareRepository
softWareService
從執行結果咱們能夠看到,容器啓動後,咱們全部加了@Repository、@Service、@Controller、@Component、@Configuration註解的Bean都被注入到了Spring IOC容器中。
在上面的例子中,在使用組件掃描時,若是咱們想過濾某些Bean,不但願全部加了@Repository、@Service、@Controller、@RestController、@Component、@Configuration這些註解的Bean都被注入到Spring IOC中,咱們該怎麼處理呢?
@ComponentScan註解有一個excludeFilters屬性,經過給該屬性設置對應的值能夠過濾掉指定條件的Bean自動注入到Spring IOC容器中,可過濾的類型咱們在上文中已經說明,這裏再也不贅述。
使用註解方式過濾指定註解的Bean很簡單,咱們修改配置類ComponentScanConfig以下,過濾掉@Controller註解的Bean自動注入Spring IOC容器中。
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}) }) //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { }
執行單元測試咱們能夠獲得以下結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareRepository
softWareService
從執行結果咱們能夠看到,容器啓動後,被@Controller註解的Bean被過濾掉了。
使用給定類型的方式過濾,即過濾指定的Bean,咱們修改配置類ComponentScanConfig以下,過濾掉SoftWareRepository這個Bean。
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}) }) //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { }
執行單元測試咱們能夠獲得以下結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareComponent
softWareService
從執行結果咱們能夠看到,容器啓動後,SoftWareRepository這個Bean被過濾掉了。
使用ASPECTJ表達式的方式過濾Bean,首先咱們須要加入切面aspectj的依賴。
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency>
咱們使用ASPECTJ表達式的方式過濾掉以Component結尾的Bean,修改ComponentScanConfig以下:
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}), @Filter(type=FilterType.ASPECTJ,pattern={"com.training.componentscan..*Component"}) }) //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { }
執行單元測試,咱們獲得以下結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
softWareService
從執行結果咱們能夠看到,容器啓動後,以Component結尾的SoftWareComponent這個Bean被過濾掉了。
咱們使用正則表達式的方式過濾掉以Service結尾的Bean,修改ComponentScanConfig以下:
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={SoftWareRepository.class}), @Filter(type=FilterType.ASPECTJ,pattern={"com.training.componentscan..*Component"}), @Filter(type=FilterType.REGEX,pattern=".*Service") }) //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { }
執行單元測試,獲得以下結果:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
componentScanConfig
從執行結果咱們能夠看到,容器啓動後,以Service結尾的SoftWareService這個Bean被過濾掉了。
咱們使用自定義過濾器過濾類名中不含有"Co"的Bean。
自定義過濾器要實現org.springframework.core.type.filter.TypeFilter接口,定義本身的過濾器ComponentFilter實現TypeFilter接口以下:
public class ComponentFilter implements TypeFilter { /** * metadataReader:讀取到的當前正在掃描的類的信息 metadataReaderFactory:能夠獲取到其餘任何類信息 */ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 獲取當前類註解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 獲取當前正在掃描的類的類信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 獲取當前類資源(類的路徑) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("---->>>>>"+className); if(!className.contains("Co")){ return true; } return false; } }
修改ComponentScanConfig以下:
@Configuration //告訴Spring這是一個配置類 @ComponentScan(basePackages = "com.training.componentscan",excludeFilters={ @Filter(type=FilterType.CUSTOM,classes={ComponentFilter.class}) }) //掃描com.training.componentscan包及其子包中被@Repository、@Service、@Controller、@RestController、@Component、@Configuration註解所標註的Bean public class ComponentScanConfig { }
執行單元測試咱們獲得以下結果:
---->>>>>com.training.componentscan.IOCTest ---->>>>>com.training.componentscan.IOCTest1 ---->>>>>com.training.componentscan.component.SoftWareComponent ---->>>>>com.training.componentscan.controller.SoftWareController ---->>>>>com.training.componentscan.filter.ComponentFilter ---->>>>>com.training.componentscan.repository.SoftWareRepository ---->>>>>com.training.componentscan.service.SoftWareService org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory componentScanConfig softWareComponent softWareController
從執行結果可知,全部沒有包含「Co」的Bean已經被所有過濾,只有類名包含"Co"的Bean注入到了Spring IOC容器中。
只包含includeFilters屬性的使用與excludeFilters屬性的使用基本一致,這裏再也不贅述。
小結:
本文咱們經過註解的方式講述了@ComponentScan的應用,以及經過實例演示的方式向你們展現了自動掃描注入時如何經過不一樣方式排除、包含知足指定條件的Bean,但願你們共勉。