@ComponentScan注解源码分析

@ComponentScan注解是扫描包,主要是通过basePackages,includeFilters,excludeFilters这三个属性确定扫描哪些类
basePackages(value): 确定扫描哪些包,String[]类型的
includeFilters:包含,值是一个Filter[]数组
excludeFilters:排除,值是一个Filter[]数组
useDefaultFilters:是否保留默认的includeFilters(其中包含@Component)
@Filter是@ComponentScan注解的内部类注解

@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 nameGenerator() default BeanNameGenerator.class;

    Class scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

    boolean useDefaultFilters() default true;

    Filter[] includeFilters() default {};

    Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {


        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class[] value() default {};

        @AliasFor("value")
        Class[] classes() default {};

        String[] pattern() default {};

    }

}

这里有一点需要注意@ComponentScan没有标注@Component注解,如果spring包扫面不到该类,那就要想办法将该类放到beanDefinitionMap中 ,比如bean工厂的后置处理器

@Filter中有4个属性,分别是
type:是枚举类,类型共五种
value:根据type的不同,这个表达式的配置方式也不同
classes:当type为ANNOTATION或者ASSIGNABLE_TYPE时,我们可以将对应的类配置在value属性中也可以配置在calsses属性中
pattern:当type是REGEX时,可以将表达式配置的pattern中

type的5中类型
ANNOTATION:指定扫描某个注解的类,这里的注解也可以是我们自定义的
ASSIGNABLE_TYPE:指定扫描某个类及子类,某个类可以是接口也可以是普通的类,如果是接口那么该类不会放进容器中,普通类可以放到容器中,子类(实现类)都会放到容器中
ASPECTJ:指定扫描AspectJ表达式相匹配的类(不常用)
REGEX:指定扫描符合正则表达式的类(不常用)
CUSTOM:指定扫描自定义的实现了org.springframework.core.type.filter.TypeFilter接口的类

ASPECTJ和REGEX两个不常用这里就不举例了,剩下的ANNOTATION, ASSIGNABLE, CUSTOM举例说明

ANNOTATION注解的方式,自定义一个注解,
@ComponentScan.Filter(type = FilterType.ANNOTATION ,classes = MyInterface.class)
只要标注了@ MyInterface的类都会放到IOC容器中

public class ComponentScanAnnotation {
    public static void main(String[] args) {
        //查找配置类.配置类有扫描类的路径,满足条件的放到容器中
        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext (ComponentScanConfiguration.class);
        Hello hello = ( Hello ) configApplicationContext.getBean ("hello");
        WorldSubClass worldSubClass = ( WorldSubClass ) configApplicationContext.getBean ("worldSubClass");
        World world = ( World ) configApplicationContext.getBean ("world");
        System.out.println (hello.getName ());
        System.out.println (worldSubClass.getName ());
        System.out.println (world.toString ());
        configApplicationContext.close ();
    }
}
@ComponentScan(basePackages = "springlearn.springComponentScan",
        includeFilters [email protected](type = FilterType.ANNOTATION ,classes = MyInterface.class)
)
public class ComponentScanConfiguration {

}
@MyInterface
@Data
public class Hello {
    private String name;
    public Hello() {
        this.name = "张三";
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MyInterface {
}

ASSIGNABLE_TYPE 指定扫描某个类及子类,某个类可以是接口也可以是普通的类,如果是接口那么该接口不会放进容器中,普通类可以放到容器中,子类(实现类)都会放到容器中
修改了includeFilters属性,多了一个Filter Type.ASSIGNABLE_TYPE

@ComponentScan(basePackages = "springlearn.springComponentScan",
        includeFilters ={@ComponentScan.Filter(type = FilterType.ANNOTATION ,classes = MyInterface.class),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE ,classes = World.class)
        }
)
public class ComponentScanConfiguration {

}
public interface World {
}
@Data
public class WorldSubClass implements World {
    private String name;

    public WorldSubClass() {
        this.name = "李四";
    }
}

自定义CUSTOM

@Data
public class DuoDuo {
    private String name;

    public DuoDuo() {
        this.name = "王五";
    }
}
@ComponentScan(basePackages = "springlearn.springComponentScan",
        includeFilters ={@ComponentScan.Filter(type = FilterType.ANNOTATION ,classes = MyInterface.class),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE ,classes = World.class ),
                @ComponentScan.Filter(type = FilterType.CUSTOM ,classes = MyTypeFilter.class ),
        }
)
public class ComponentScanConfiguration {

}

public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获得当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获得当前正在扫描的类的资源信息
        Resource resource = metadataReader.getResource();
        //获得当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
//全类名
        String name = classMetadata.getClassName();
//如果全类名包含DuoDuo,则放到IOC容器中
        if(name.contains("DuoDuo")){
            return true;
        }
        return false;
    }
}

下面对@ComponentScan进行源码分析
从ComponentScanAnnotationParser#parse方法入手,spring是如何调用到这个方法是一个比较长的调用链,涉及到最重要的类ConfigurationClassPostProcessor的bean工厂的后置注册器postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
-> ConfigurationClassPostProcessor#processConfigBeanDefinitions
-> ConfigurationClassPostProcessor#processConfigurationClass
-> ConfigurationClassPostProcessor#doProcessConfigurationClass
->ComponentScanAnnotationParser#parse
上面也是简化的调用链,重点分析ComponentScanAnnotationParser#parse方法

public Set parse(AnnotationAttributes componentScan, final String declaringClass) {
//首先是扫描器, componentScan.getBoolean("useDefaultFilters")代表的就是
//@ComponentScan useDefaultFilters的属性,其作用就是, //ClassPathBeanDefinitionScanner在创建的时候,会自己创建3个includeFilters,其中既有
//@Component,其余两个是jdk自带的,一般不会使用
//useDefaultFilters如果为false,那么就不会创建这3个过滤器
//比如只想扫面自定义注解的类,不扫面@Component注释的类,就要将useDefaultFilters设置//为false
   ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
         componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

   Class generatorClass = componentScan.getClass("nameGenerator");
   boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
   scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
         BeanUtils.instantiateClass(generatorClass));

   ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
   if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
      scanner.setScopedProxyMode(scopedProxyMode);
   }
   else {
      Class resolverClass = componentScan.getClass("scopeResolver");
      scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
   }

   scanner.setResourcePattern(componentScan.getString("resourcePattern"));
//获取includeFilters
   for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
// typeFiltersFor就会根据传入的类型,上面提到type的5中类型,创建filter
      for (TypeFilter typeFilter : typeFiltersFor(filter)) {
         scanner.addIncludeFilter(typeFilter);
      }
   }
// 获取excludeFilters
   for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
      for (TypeFilter typeFilter : typeFiltersFor(filter)) {
         scanner.addExcludeFilter(typeFilter);
      }
   }

   boolean lazyInit = componentScan.getBoolean("lazyInit");
   if (lazyInit) {
      scanner.getBeanDefinitionDefaults().setLazyInit(true);
   }
//包名
   Set basePackages = new LinkedHashSet<>();
   String[] basePackagesArray = componentScan.getStringArray("basePackages");
   for (String pkg : basePackagesArray) {
      String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
      Collections.addAll(basePackages, tokenized);
   }
   for (Class clazz : componentScan.getClassArray("basePackageClasses")) {
      basePackages.add(ClassUtils.getPackageName(clazz));
   }
   if (basePackages.isEmpty()) {
      basePackages.add(ClassUtils.getPackageName(declaringClass));
   }
//默认加了不包含过滤器,其作用是在扫面包下的所有类的时候,可能会扫面标注了//@ComponentScan的类,这个类其实就是本身的类, 这里就是ComponentScanConfiguration类
//把它排除掉,不需要重复的扫面, declaringClass= ComponentScanConfiguration
   scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
      @Override
      protected boolean matchClassName(String className) {
         return declaringClass.equals(className);
      }
   });
//开始扫面,spring中有do字样的,一般都是开始干活了
   return scanner.doScan(StringUtils.toStringArray(basePackages));

doScan方法,这个方法我也就关心了一个方法
findCandidateComponents(basePackage)
->scanCandidateComponents(basePackage)
-> isCandidateComponent(metadataReader)

scanCandidateComponents(basePackage)方法

private Set scanCandidateComponents(String basePackage) {
   Set candidates = new LinkedHashSet<>();
   try {
//获取classPath+包名下所有.class结尾的文件,并解析成源文件
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + '/' + this.resourcePattern;
      Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
      boolean traceEnabled = logger.isTraceEnabled();
      boolean debugEnabled = logger.isDebugEnabled();
      for (Resource resource : resources) {
         if (traceEnabled) {
            logger.trace("Scanning " + resource);
         }
         if (resource.isReadable()) {
            try {
               MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//判断类是否满足过滤器条件,
               if (isCandidateComponent(metadataReader)) {
                  ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                  sbd.setSource(resource);
                  if (isCandidateComponent(sbd)) {
                     if (debugEnabled) {
                        logger.debug("Identified candidate component class: " + resource);
                     }
                     candidates.add(sbd);
                  }
                  else {
                     if (debugEnabled) {
                        logger.debug("Ignored because not a concrete top-level class: " + resource);
                     }
                  }
               }
               else {
                  if (traceEnabled) {
                     logger.trace("Ignored because not matching any filter: " + resource);
                  }
               }
            }
            catch (Throwable ex) {
               throw new BeanDefinitionStoreException(
                     "Failed to read candidate component class: " + resource, ex);
            }
         }
         else {
            if (traceEnabled) {
               logger.trace("Ignored because not readable: " + resource);
            }
         }
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
   }
   return candidates;
}

isCandidateComponent(metadataReader)方法

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return false;
      }
   }
//有默认的过滤器(其中包含@Component),还有自己标注的过滤器
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, getMetadataReaderFactory())) {
         return isConditionMatch(metadataReader);
      }
   }
   return false;
}

源码分析到这,就结束了.

你可能感兴趣的:(@ComponentScan注解源码分析)