context:component-scan 标签解析

1.作用

扫描classpath下带有注解的类,注册成spring bean。Spring 默认提供的注解包括@Component,@Repository,

@Service,@Controller,@RestController,@ControllerAdvice, @Configuration。

它有一个annotation-config属性默认是ture,它的作用和 一样。激活@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext ,@PersistenceUnit注解

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
   String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
   basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
   String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

   // Actually scan for bean definitions and register them.
   ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
   Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
   registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

   return null;
}
我们看扫描完成后,有一个注册组件的方法 registerComponents(),我们看这个方法

// Register annotation config processors, if necessary.
boolean annotationConfig = true;
if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
   annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
}
if (annotationConfig) {
   Set<BeanDefinitionHolder> processorDefinitions =
         AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
   for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
      compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
   }
}
这句代码就是处理@Required,@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext ,@PersistenceUnit相关注解

Set<BeanDefinitionHolder> processorDefinitions =
      AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
我们看annotation-config 标签的解析器代码,有同样的一段代码。

registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {

   @Override
   public BeanDefinition parse(Element element, ParserContext parserContext) {
      Object source = parserContext.extractSource(element);

      // Obtain bean definitions for all relevant BeanPostProcessors.
      Set processorDefinitions =
            AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);

      // Register component for the surrounding  element.
      CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
      parserContext.pushContainingComponent(compDefinition);

      // Nest the concrete beans in the surrounding component.
      for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
         parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
      }

      // Finally register the composite component.
      parserContext.popAndRegisterContainingComponent();

      return null;
   }

}

所以当我们有context:component-scan标签时,可以省略annotation-config 标签了。

2.流程

ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
主要是创建ClassPathBeanDefinitionScanner对象然后扫描指定的包路径。

ClassPathBeanDefinitionScanner scanner = createScanner(readerContext, useDefaultFilters);

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
   return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters);
}

我们看创建ClassPathBeanDefinitionScanner源代码有下面一句

public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
   if (useDefaultFilters) {
      registerDefaultFilters();
   }
   this.environment = environment;
}
protected void registerDefaultFilters() {
   this.includeFilters.add(new AnnotationTypeFilter(Component.class));
   ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Classextends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
      logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
   }
   try {
      this.includeFilters.add(new AnnotationTypeFilter(
            ((Classextends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
      logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
   }
   catch (ClassNotFoundException ex) {
      // JSR-330 API not available - simply skip.
   }
}
默认扫描Component注解。实际上@Repository, @Service,@Controller,@RestController,@ControllerAdvice, @Configuration。上面都是有Component注解。

我们看扫描指定包的方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
   Assert.notEmpty(basePackages, "At least one base package must be specified");
   Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
   for (String basePackage : basePackages) {
      Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
      for (BeanDefinition candidate : candidates) {
         ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
         candidate.setScope(scopeMetadata.getScopeName());
         String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
         if (candidate instanceof AbstractBeanDefinition) {
            postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
         }
         if (candidate instanceof AnnotatedBeanDefinition) {
            AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
         }
         if (checkCandidate(beanName, candidate)) {
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            beanDefinitions.add(definitionHolder);
            registerBeanDefinition(definitionHolder, this.registry);
         }
      }
   }
   return beanDefinitions;
}
通过扫描包下面的每一个Class(findCandidateComponents方法),读取信息看是否匹配

MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) 
我们看一下怎么算匹配,首先看是否match,然后判断Profile注解指定的值

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
      if (tf.match(metadataReader, this.metadataReaderFactory)) {
         return false;
      }
   }
   for (TypeFilter tf : this.includeFilters) {
      if (tf.match(metadataReader, this.metadataReaderFactory)) {
         AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
         if (!metadata.isAnnotated(Profile.class.getName())) {
            return true;
         }
         AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
         return this.environment.acceptsProfiles(profile.getStringArray("value"));
      }
   }
   return false;
}
我们看match方法

public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {

   // This method optimizes avoiding unnecessary creation of ClassReaders
   // as well as visiting over those readers.
   if (matchSelf(metadataReader)) {
      return true;
   }
AnnotationTypeFilter实现了matchSelf方法,即匹配是否有注解Component。

@Override
protected boolean matchSelf(MetadataReader metadataReader) {
   AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
   return metadata.hasAnnotation(this.annotationType.getName()) ||
         (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}

你可能感兴趣的:(spring)