spring 注解学习 二 ComponentScan注解的使用
@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中,注解定义如下。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT; String resourcePattern() default "**/*.class"; boolean useDefaultFilters() default true; ComponentScan.Filter[] includeFilters() default {}; ComponentScan.Filter[] excludeFilters() default {}; boolean lazyInit() default false; @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Filter { FilterType type() default FilterType.ANNOTATION; @AliasFor("classes") Class<?>[] value() default {}; @AliasFor("value") Class<?>[] classes() default {}; String[] pattern() default {}; } }
basePackages与value:
用于指定包的路径,进行扫描。默认情况下是扫描配置类所在的包及其子包下的类
basePackageClasses:
用于指定某个类的包的路径进行扫描
nameGenerator:
bean的名称的生成器
useDefaultFilters:
是否开启对@Component,@Repository,@Service,@Controller的类进行检测
(1)默认情况下是true。在basePackages指定的路径以及子路径下所有被@Component ,@Repository,@Service,@Controller注解标记的类都会被扫描,并注入到Spring 容器。
(2)如果useDefaultFilters的是false话,不扫描 在basePackages指定的路径以及子路径下所有被@Component ,@Repository,@Service,@Controller注解标记的类,这些类即使被上面四个注解标记,也不会注入到Spring容器中。
includeFilters:
包含的过滤条件,一般当useDefaultFilters的值为false时使用,当useDefaultFilters为false时,includeFilters指定的就是需要进行扫描并注入的条件
FilterType.ANNOTATION:按照注解过滤
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:正则
FilterType.CUSTOM:自定义规则
excludeFilters:
排除的过滤条件,一般useDefaultFilters为true时使用,excludeFilters的指就是basePackages指定的路径以及子路径下排除的条件。
案例1
@Configuration @ComponentScan(basePackages = {"com.zhang"}, useDefaultFilters=true, excludeFilters ={@Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ANNOTATION,classes={Service.class})})
(1)basePaceages指定了 com.zhang这个包,useDefaultFilters的值为true。如果不考虑excludeFilters ,这个两个属性组合的起来就是在 com.zhang及其子包下所有被@Component ,@Repository,@Service,@Controller这四个注解标注的类,都会被扫描并注入到Spring容器中。
(2)excludeFilters 属性指定了要排除掉被@Controller与@Service两个注解。在basePaceages与useDefaultFilters两个属性的基础上进行排除,那么最后扫描的就是 com.zhang包及其子包下的被@Component ,@Repository标记的类。
案例2
@ComponentScan(basePackages = {"com.zhang"}, useDefaultFilters=false, includeFilters ={@Filter(type=FilterType.ANNOTATION,classes={Controller.class})})
includeFilters 也是在basePackages与useDefaultFilters组合后的基础上添加一些特定的类。本例中的意思是只扫描com.zhang及其子包下被@Controller注解标记的类
案例3 自定义规则 FilterType.CUSTOM
@Configuration @ComponentScan(value = "com.personal.spring.bean",useDefaultFilters = true, excludeFilters ={@ComponentScan.Filter(type= FilterType.CUSTOM,classes= MyTypeFilter.class)} ) public class SpringConfig { }
在com.personal.spring.bean包下有bean
package com.personal.spring.bean; import lombok.Data; import org.springframework.stereotype.Component; @Data @Component public class User { private String userName; private String userCode; }
MyTypeFilter过滤器
package com.personal.spring.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; public class MyTypeFilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); System.out.println(annotationMetadata.getAnnotationTypes()); ClassMetadata classMetadata = metadataReader.getClassMetadata(); System.out.println(classMetadata.getClassName()); Resource resource = metadataReader.getResource(); System.out.println(resource.getFilename()); System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++"); return true; } }
测试代码:
package com.personal.spring.main; import com.personal.spring.config.SpringConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.util.Arrays; public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class); String[] beanDefinitionNames = context.getBeanDefinitionNames(); Arrays.stream(beanDefinitionNames).forEach(x-> System.out.println(x)); } }
运行结果:
[org.springframework.stereotype.Component] com.personal.spring.bean.User User.class ++++++++++++++++++++++++++++++++++++++++++++++++++ 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 springConfig
案例三中,我们发现useDefaultFilters等于true的情况下,User类也被@Componet注解标注的情况下,还是没有注入到容器。原因就是在
excludeFilters中使用自定义规则,如果返回true 是排除当前的类,如果返回false,是把当前类加入到容器、
includeFilters中使用自定义规则,如果返回true,是把当前类加入到容器,如果返回false则是把当前类排除