@Override
  protected void doParse(
      Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
    Map<String, ParsingModuleInfo> classes =
        parseSpecificBeans(
            element, parserContext, builder.getRawBeanDefinition(), and(beansNs(), name("bean")));

    ElementSelector searchPackages = and(sameNs(element), name("search-packages"));
    ElementSelector searchClasses = and(sameNs(element), name("search-classes"));
    ModuleDefinitionScanner scanner = getScanner(parserContext);

    for (Element subElement : subElements(element)) {
      Pattern classNamePattern = null;
      String typeName = null;
      String moduleName = null;
      String classResourceName = null;

      if (searchPackages.accept(subElement)) {
        String packageName =
            assertNotNull(
                normalizeClassName(subElement.getAttribute("packages")),
                "no package name provided for search-packages");

        classNamePattern = compileClassName(packageName, MATCH_PREFIX);
        typeName =
            assertNotNull(trimToNull(subElement.getAttribute("type")), "no type name provided");
        classResourceName = classNameToPathName(packageName) + "/**/*.class";

        log.trace("Searching in packages: {}, moduleType={}", packageName, typeName);
      } else if (searchClasses.accept(subElement)) {
        String className =
            assertNotNull(
                normalizeClassName(subElement.getAttribute("classes")),
                "no class name provided for search-classes");

        classNamePattern = compileClassName(className, MATCH_PREFIX);
        typeName =
            assertNotNull(trimToNull(subElement.getAttribute("type")), "no type name provided");
        moduleName =
            assertNotNull(trimToNull(subElement.getAttribute("name")), "no module name provided");
        classResourceName = classNameToPathName(className);

        if (classResourceName.endsWith("**")) {
          classResourceName += "/*.class";
        } else {
          classResourceName += ".class";
        }

        log.trace(
            "Searching for classes: {}, moduleType={}, moduleName={}",
            new Object[] {className, typeName, moduleName});
      }

      boolean includeAbstractClasses =
          "true".equalsIgnoreCase(trimToNull(subElement.getAttribute("includeAbstractClasses")));

      if (classResourceName != null) {
        // 处理所有的include/exclude filters
        ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
        List<TypeFilter> includes = createLinkedList();
        List<TypeFilter> excludes = createLinkedList();

        parseTypeFilters(subElement, classLoader, includes, excludes);

        ModuleTypeFilter filter =
            new ModuleTypeFilter(classes, classNamePattern, typeName, moduleName, includes);

        // 事实上,只有一个顶级的include filter,其它的include filter被这一个moduleTypeFilter所调用。
        scanner.addIncludeFilter(filter);

        // Exclude filter比较简单,直接加到scanner中即可。
        for (TypeFilter exclude : excludes) {
          scanner.addExcludeFilter(exclude);
        }

        scanner.setBeanNameGenerator(filter);
        scanner.setResourcePattern(classResourceName.replace('?', '*'));
        scanner.setIncludeAbstractClasses(includeAbstractClasses);
        scanner.setBeanDefinitionDefaults(getBeanDefinitionDefaults(subElement, parserContext));

        int found = scanner.scan("");

        log.debug("Found {} module classes with pattern: {}", found, classResourceName);
      }
    }

    postProcessItems(element, parserContext, builder, classes, "search-packages or search-classes");
  }