戴着假發的程序員出品 抖音ID:戴着假發的程序員 歡迎關注
[查看視頻教程]
這里的includeFilters和context:include-filter標簽的作用完全一致。
我們已經知道ComponentScan的配置可以通知spring掃描擁有spring標准注解的類。這些標注大致是:@Component、@Controller、@Service、@Repository。但是我們也可以通過includeFilters屬性配置通知spring掃描一些沒有標准注解但是我們希望spring幫我們管理的類。
includeFilters的值是一個數組,可以配置多個,includeFilters中配置的是一個Filter類型的注解。Filter的源碼如下:
1 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) 2 @java.lang.annotation.Target({}) 3 static @interface Filter { 4 org.springframework.context.annotation.FilterType type() default org.springframework.context.annotation.FilterType.ANNOTATION; 5 6 @org.springframework.core.annotation.AliasFor("classes") 7 java.lang.Class<?>[] value() default {}; 8 9 @org.springframework.core.annotation.AliasFor("value") 10 java.lang.Class<?>[] classes() default {}; 11 12 java.lang.String[] pattern() default {}; 13 }
Filter中有4個屬性,分別是
type:用來配置Filter的類型,這個類型是一個枚舉,這個類型一共有五種,下面再詳細解釋。
value:根據type的不同,這個表達式的配置方式也不同。
classes:當我們的type為ANNOTATION或者ASSIGNABLE_TYPE時,我們可以將對應的類配置在value屬性中也可以配置在calsses屬性中
pattern:當我們的type是REGEX時,我們可以將表達式配置的pattern中。
type屬性的五個值:
ANNOTATION:-指定掃描使用某個注解的類
ASSIGNABLE_TYPE:指定掃描某個接口派生出來的類
ASPECTJ:指定掃描AspectJ表達式相匹配的類
REGEX:指定掃描符合正則表達式的類
CUSTOM:指定掃描自定義的實現了org.springframework.core.type.filter.TypeFilter接口的類
就這個五個類型,我准備五個案例看看
[1]ANNOTATION:-指定掃描使用某個注解的類,將其加載進spring的容器。
我們准備如下的類目錄結構:
其中Person類實現:
Person有Spring的標准注解@Component.
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Component//Person類交給spring管理 7 public class Person{ 8 public Person(){ 9 System.out.println("實例化Person類"); 10 } 11 }
Dog類的實現:
Dog類並沒有Spring的標准注解,添加添加了我們自定義的注解:
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @DkAnnotation 7 public class Dog { 8 public Dog(){ 9 System.out.println("實例化Dog類"); 10 } 11 }
我們自定的注解@DkAnnotation
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public @interface DkAnnotation { 7 }
添加一個配置類:
配置類中給ComponentScan添加屬性excludeFilters,類型為ANNOTATION,value為DkAnnotation.class。當然也可以使用classes代替value,注意value和classes都是數組,可以同時配置多個。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Configuration() 7 @ComponentScan( 8 basePackages = "com. st.dk.demo6.beans", 9 includeFilters = {@ComponentScan.Filter(type= FilterType.ANNOTATION,value= DkAnnotation.class)} 10 ) 11 public class AppConfig { 12 }
測試:
1 @Test 2 public void testIncludeFilters(){ 3 ApplicationContext ac = 4 new AnnotationConfigApplicationContext(AppConfig.class); 5 }
結果:
我們會發現spring會將有標注注解的Person類和我們有我們自定義注解的Dog都加載。
[2]ASSIGNABLE_TYPE:指定掃描某個接口派生出來的類
案例:
我們修改上面的案例,添加一個接口Info。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public interface Info { 7 }
修改Dog類,刪除Dog類上方的注解,但是讓Dog類實現接口Info。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public class Dog implements Info { 7 public Dog(){ 8 System.out.println("實例化Dog類"); 9 } 10 }
修改配置類,修改type屬性為ASSIGNABLE_TYPE,value或者classes屬性配置為Info .class。表示實現了Info接口的類要求spring加載。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Configuration() 7 @ComponentScan( 8 basePackages = "com. st.dk.demo6.beans", 9 includeFilters = {@ComponentScan.Filter(type= FilterType.ASSIGNABLE_TYPE,value={Info.class})} 10 ) 11 public class AppConfig { 12 }
再測試,我們會發現spring依然會加載Dog類。
[3]ASPECTJ:指定掃描AspectJ表達式相匹配的類,比如要求加載某個類的派生類
案例:
我們添加一個Animal類:
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public class Animal { 7 }
修改Dog,繼承Animal。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public class Dog extends Animal { 7 public Dog(){ 8 System.out.println("實例化Dog類"); 9 } 10 }
修改配置類,type配置為ASPECTJ,這里注意去掉value或者calsses屬性,添加pattern屬性,值為:com. st.dk.demo6.beans.Animal+
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Configuration() 7 @ComponentScan( 8 basePackages = "com. st.dk.demo6.beans", 9 includeFilters = {@ComponentScan.Filter(type= FilterType.ASPECTJ,pattern = "com. st.dk.demo6.beans.Animal+")} 10 ) 11 public class AppConfig { 12 }
再測試,我們會發現spring依然會加載Dog類。
[4]REGEX:指定掃描符合正則表達式的類
我們可以通過REGEX配置一個正則表達式,spring會根據正則匹配加載對應的類。
案例:我們修改Dog類,不實現接口,不繼承其他類,沒有注解。
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public class Dog{ 7 public Dog(){ 8 System.out.println("實例化Dog類"); 9 } 10 }
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Configuration() 7 @ComponentScan( 8 basePackages = "com. st.dk.demo6.beans", 9 includeFilters = {@ComponentScan.Filter(type= FilterType.REGEX,pattern = ".*.*og")} 10 ) 11 public class AppConfig { 12 }
再測試,我們會發現spring依然會加載Dog類。
[5]CUSTOM:指定掃描自定義的實現了org.springframework.core.type.filter.TypeFilter接口的類
CUSTOM允許我們自定義加載策略,我們可以自己實現一個TypeFilter,實現自己的加載策略。
案例:我們自己實現一個Filter,用來加載Dog類。添加一個自己的類實現接口TypeFilter
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 public class DkFilter implements TypeFilter { 7 //關於metadataReader和metadataReaderFactory可以關注spring源碼解讀部分 8 @Override 9 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { 10 //獲取當前正在掃描的類的類名 11 String className = metadataReader.getClassMetadata().getClassName(); 12 //判斷是不是Dog的class 13 if(className.equals(Dog.class.getName())){ 14 //返回true表示讓spring加載當前的類. 15 return true; 16 } 17 //返回false表示不讓spring加載當前類 18 return false; 19 } 20 }
修改配置類,type修改為CUSTOM,value或者classes中配置DkFilter.class
1 /** 2 * @author 戴着假發的程序員 3 * 4 * @description 5 */ 6 @Configuration() 7 @ComponentScan( 8 basePackages = "com. st.dk.demo6.beans", 9 includeFilters = {@ComponentScan.Filter(type= FilterType.CUSTOM,value = DkFilter.cl 10 )} 11 ) 12 public class AppConfig { 13 }
再測試,我們會發現spring依然會加載Dog類。