Spring源码分析之组件扫描(上)

本文深入解析了Spring框架中组件扫描的实现原理,详细介绍了如何通过context命名空间和ComponentScan注解进行组件扫描,以及ComponentScanBeanDefinitionParser类如何解析组件扫描标签。

关于组件扫描的标签是context,对应的命名空间处理类为ContextNamespaceHandler,可以使用注解ComponentScan,但是还是需要设置标签annotation-config,也可以直接使用标签component-scan

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
  public void init() {
    registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
    registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
    registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
    registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
    registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
  }
}

标签component-scan对应的解析类为ComponentScanBeanDefinitionParser,首先获取基础包路径并解析,解析属性base-package


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;
}

创建bean定义扫描类,设置一些必要的属性


protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
  boolean useDefaultFilters = true;
  if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
    useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
  }

  // Delegate bean definition registration to scanner class.
  ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
  scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader());
  scanner.setEnvironment(parserContext.getReaderContext().getEnvironment());
  scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
  scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

  if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
    scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
  }

  try {
    parseBeanNameGenerator(element, scanner);
  }
  catch (Exception ex) {
    parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
  }

  try {
    parseScope(element, scanner);
  }
  catch (Exception ex) {
    parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
  }

  parseTypeFilters(element, scanner, parserContext);

  return scanner;
}

默认使用默认的过滤机制,也就是默认扫描带有注解Component和Name的bean


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

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
  this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
  super(useDefaultFilters, environment);
  Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  this.registry = registry;
  // Determine ResourceLoader to use.
  if (this.registry instanceof ResourceLoader) {
    setResourceLoader((ResourceLoader) this.registry);
  }
}

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.
  }
}

解析类型过滤器,这里会解析属性include-filter和exclude-filter的内容


protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
  // Parse exclude and include filter elements.
  ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
  NodeList nodeList = element.getChildNodes();
  for (int i = 0; i < nodeList.getLength(); i++) {
    Node node = nodeList.item(i);
    if (node.getNodeType() == Node.ELEMENT_NODE) {
      String localName = parserContext.getDelegate().getLocalName(node);
      try {
        if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
          TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
          scanner.addIncludeFilter(typeFilter);
        }
        else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
          TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
          scanner.addExcludeFilter(typeFilter);
        }
      }
      catch (Exception ex) {
        parserContext.getReaderContext().error(
            ex.getMessage(), parserContext.extractSource(element), ex.getCause());
      }
    }
  }
}

根据不同的过滤类型生成不同的过滤器

protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
  String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
  String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
  expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
  try {
    if ("annotation".equals(filterType)) {
      return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
    }
    else if ("assignable".equals(filterType)) {
      return new AssignableTypeFilter(classLoader.loadClass(expression));
    }
    else if ("aspectj".equals(filterType)) {
      return new AspectJTypeFilter(expression, classLoader);
    }
    else if ("regex".equals(filterType)) {
      return new RegexPatternTypeFilter(Pattern.compile(expression));
    }
    else if ("custom".equals(filterType)) {
      Class<?> filterClass = classLoader.loadClass(expression);
      if (!TypeFilter.class.isAssignableFrom(filterClass)) {
        throw new IllegalArgumentException(
            "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
      }
      return (TypeFilter) BeanUtils.instantiateClass(filterClass);
    }
    else {
      throw new IllegalArgumentException("Unsupported filter type: " + filterType);
    }
  }
  catch (ClassNotFoundException ex) {
    throw new FatalBeanException("Type filter class not found: " + expression, ex);
  }
}

扫描bean定义


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;
}

寻找所有的候选组件,给基础包名加上classpath*:前缀,解析并获取该路径下的所有资源,判断资源是否可读,并且获取元数据读取器

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
  Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
  try {
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
        resolveBasePackage(basePackage) + "/" + this.resourcePattern;
    Resource[] resources = this.resourcePatternResolver.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 = this.metadataReaderFactory.getMetadataReader(resource);
          if (isCandidateComponent(metadataReader)) {
            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
            sbd.setResource(resource);
            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;
}

判断是否满足我们设置的过滤要求

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)) {
      return isConditionMatch(metadataReader);
    }
  }
  return false;
}

再判断返回底层类是表示具体类,即既不是接口也不是抽象类。确定底层类是否是独立的,即它是一个顶层类还是一个嵌套类(静态内部类),它可以独立于一个封闭类构造。

protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
  return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent());
}

然后对这些bean定义生成自己的名字

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  if (definition instanceof AnnotatedBeanDefinition) {
    String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
    if (StringUtils.hasText(beanName)) {
      // Explicit bean name found.
      return beanName;
    }
  }
  // Fallback: generate a unique default bean name.
  return buildDefaultBeanName(definition, registry);
}

首先判断是否是注解型bean定义,从注解中获取bean名字


protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
  AnnotationMetadata amd = annotatedDef.getMetadata();
  Set<String> types = amd.getAnnotationTypes();
  String beanName = null;
  for (String type : types) {
    AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
    if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
      Object value = attributes.get("value");
      if (value instanceof String) {
        String strVal = (String) value;
        if (StringUtils.hasLength(strVal)) {
          if (beanName != null && !strVal.equals(beanName)) {
            throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
                "component names: '" + beanName + "' versus '" + strVal + "'");
          }
          beanName = strVal;
        }
      }
    }
  }
  return beanName;
}

判断是否带有以下几种注解,如果设置了value方法的话,就使用它为名字


private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";

protected boolean isStereotypeWithNameValue(String annotationType,
    Set<String> metaAnnotationTypes, Map<String, Object> attributes) {

  boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
      (metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
      annotationType.equals("javax.annotation.ManagedBean") ||
      annotationType.equals("javax.inject.Named");

  return (isStereotype && attributes != null && attributes.containsKey("value"));
}

如果没有设置名字的话就需要生成一个唯一的名字


protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
  return buildDefaultBeanName(definition);
}

protected String buildDefaultBeanName(BeanDefinition definition) {
  String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
  return Introspector.decapitalize(shortClassName);
}

获取普通的类名


public static String getShortName(String className) {
  Assert.hasLength(className, "Class name must not be empty");
  int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
  int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
  if (nameEndIndex == -1) {
    nameEndIndex = className.length();
  }
  String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
  shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
  return shortName;
}

判断类名,首字母小写,“FooBah”变为“fooBah”,“X”变为“x”,或者不变,“URL”保持为“URL”

public static String decapitalize(String name) {
    if (name == null || name.length() == 0) {
        return name;
    }
    if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                    Character.isUpperCase(name.charAt(0))){
        return name;
    }
    char chars[] = name.toCharArray();
    chars[0] = Character.toLowerCase(chars[0]);
    return new String(chars);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值