context:component-scan 标签解析

来源:互联网 发布:林向正手抛网淘宝价格 编辑:程序博客网 时间:2024/05/21 09:50

1.作用

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

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

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

@Overridepublic 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<BeanDefinitionHolder> processorDefinitions =            AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);      // Register component for the surrounding <context:annotation-config> 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(            ((Class<? extends 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(            ((Class<? extends 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。

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

原创粉丝点击