戴着假发的程序员出品 抖音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类。