Spring的強大之處不單單是提供了IOC容器,可以經過過濾規則指定排除和只包含哪些組件,它還可以經過自定義TypeFilter來指定過濾規則。若是Spring內置的過濾規則不可以知足咱們的需求,那麼咱們就能夠經過自定義TypeFilter來實現咱們本身的過濾規則。java
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotationgit
在使用@ComponentScan註解實現包掃描時,咱們可使用@Filter指定過濾規則,在@Filter中,經過type指定過濾的類型。而@Filter註解的type屬性是一個FilterType枚舉,以下所示。github
package org.springframework.context.annotation; public enum FilterType { ANNOTATION, ASSIGNABLE_TYPE, ASPECTJ, REGEX, CUSTOM }
每一個枚舉值的含義以下所示。正則表達式
(1)ANNOTATION:按照註解進行過濾。spring
例如,使用@ComponentScan註解進行包掃描時,按照註解只包含標註了@Controller註解的組件,以下所示。微信
@ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}) }, useDefaultFilters = false)
(2)ASSIGNABLE_TYPE:按照給定的類型進行過濾。ide
例如,使用@ComponentScan註解進行包掃描時,按照給定的類型只包含PersonService類(接口)或其子類(實現類或子接口)的組件,以下所示。學習
@ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonService.class}) }, useDefaultFilters = false)
此時,只要是PersonService類型的組件,都會被加載到容器中。也就是說:當PersonService是一個Java類時,Person類及其子類都會被加載到Spring容器中;當PersonService是一個接口時,其子接口或實現類都會被加載到Spring容器中。測試
(3)ASPECTJ:按照ASPECTJ表達式進行過濾ssr
例如,使用@ComponentScan註解進行包掃描時,按照ASPECTJ表達式進行過濾,以下所示。
@ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.ASPECTJ, classes = {AspectJTypeFilter.class}) }, useDefaultFilters = false)
(4)REGEX:按照正則表達式進行過濾
例如,使用@ComponentScan註解進行包掃描時,按照正則表達式進行過濾,以下所示。
@ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.REGEX, classes = {RegexPatternTypeFilter.class}) }, useDefaultFilters = false)
(5)CUSTOM:按照自定義規則進行過濾。
若是實現自定義規則進行過濾時,自定義規則的類必須是org.springframework.core.type.filter.TypeFilter接口的實現類。
例如,按照自定義規則進行過濾,首先,咱們須要建立一個org.springframework.core.type.filter.TypeFilter接口的實現類MyTypeFilter,以下所示。
public class MyTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { return false; } }
當咱們實現TypeFilter接口時,須要實現TypeFilter接口中的match()方法,match()方法的返回值爲boolean類型。當返回true時,表示符合規則,會包含在Spring容器中;當返回false時,表示不符合規則,不會包含在Spring容器中。另外,在match()方法中存在兩個參數,分別爲MetadataReader類型的參數和MetadataReaderFactory類型的參數,含義分別以下所示。
接下來,使用@ComponentScan註解進行以下配置。
@ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) }, useDefaultFilters = false)
在FilterType枚舉中,ANNOTATION和ASSIGNABLE_TYPE是比較經常使用的,ASPECTJ和REGEX不太經常使用,若是FilterType枚舉中的類型沒法知足咱們的需求時,咱們也能夠經過實現org.springframework.core.type.filter.TypeFilter接口來自定義過濾規則,此時,將@Filter中的type屬性設置爲FilterType.CUSTOM,classes屬性設置爲自定義規則的類對應的Class對象。
在項目的io.mykit.spring.plugins.register.filter包下新建MyTypeFilter,並實現org.springframework.core.type.filter.TypeFilter接口。此時,咱們先在MyTypeFilter類中打印出當前正在掃描的類名,以下所示。
package io.mykit.spring.plugins.register.filter; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.ClassMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.filter.TypeFilter; import java.io.IOException; /** * @author binghe * @version 1.0.0 * @description 自定義過濾規則 */ public class MyTypeFilter implements TypeFilter { /** * metadataReader:讀取到的當前正在掃描的類的信息 * metadataReaderFactory:能夠獲取到其餘任務類的信息 */ @Override 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); return false; } }
接下來,咱們在PersonConfig類中配置自定義過濾規則,以下所示。
@Configuration @ComponentScans(value = { @ComponentScan(value = "io.mykit.spring", includeFilters = { @Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) }, useDefaultFilters = false) }) public class PersonConfig { @Bean("person") public Person person01(){ return new Person("binghe001", 18); } }
接下來,咱們運行SpringBeanTest類中的testComponentScanByAnnotation()方法進行測試,輸出的結果信息以下所示。
-----> io.mykit.spring.test.SpringBeanTest -----> io.mykit.spring.bean.Person -----> io.mykit.spring.plugins.register.controller.PersonController -----> io.mykit.spring.plugins.register.dao.PersonDao -----> io.mykit.spring.plugins.register.filter.MyTypeFilter -----> io.mykit.spring.plugins.register.service.PersonService 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 personConfig person
能夠看到,已經輸出了當前正在掃描的類的名稱,同時,除了Spring內置的bean名稱外,只輸出了personConfig和person,沒有輸出使用@Repository、@Service、@Controller註解標註的組件名稱。這是由於當前PersonConfig上標註的@ComponentScan註解是使用自定義的規則,而在MyTypeFilter自定義規則的實現類中,直接返回了false值,將全部的bean都排除了。
咱們能夠在MyTypeFilter類中簡單的實現一個規則,例如,當前掃描的類名稱中包含有字符串Person,就返回true,不然返回false。此時,MyTypeFilter類中match()方法的實現以下所示。
@Override 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); return className.contains("Person"); }
此時,在io.mykit.spring包下的全部類都會經過MyTypeFilter類的match()方法,來驗證類名是否包含Person,若是包含則返回true,不然返回false。
咱們再次運行SpringBeanTest類中的testComponentScanByAnnotation()方法進行測試,輸出的結果信息以下所示。
-----> io.mykit.spring.test.SpringBeanTest -----> io.mykit.spring.bean.Person -----> io.mykit.spring.plugins.register.controller.PersonController -----> io.mykit.spring.plugins.register.dao.PersonDao -----> io.mykit.spring.plugins.register.filter.MyTypeFilter -----> io.mykit.spring.plugins.register.service.PersonService 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 personConfig person personController personDao personService
此時,結果信息中輸出了使用@Repository、@Service、@Controller註解標註的組件名稱,分別爲:personDao、personService和personController。
好了,我們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一塊兒學習一塊兒進步!!
項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation
若是以爲文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習Spring註解驅動開發。公衆號回覆「spring註解」關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發再也不迷茫。