Spring's annotation class registration analysis

Spring's annotation class registration analysis analysis

1. Start with xml parsing

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

   @Override
   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());
   }

}

spring reads and registers various NamspaceHandlers of spring-handler.propertise,

Then get the corresponding ContextNamespaceHandler according to the uri of each xml element, thereby finding the parsing class corresponding to the tag

ComponentScanBeanDefinitionParser

 

public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {

   private static final String BASE_PACKAGE_ATTRIBUTE = "base-package";

   private static final String RESOURCE_PATTERN_ATTRIBUTE = "resource-pattern";

   private static final String USE_DEFAULT_FILTERS_ATTRIBUTE = "use-default-filters";

   private static final String ANNOTATION_CONFIG_ATTRIBUTE = "annotation-config";

   private static final String NAME_GENERATOR_ATTRIBUTE = "name-generator";

   private static final String SCOPE_RESOLVER_ATTRIBUTE = "scope-resolver";

   private static final String SCOPED_PROXY_ATTRIBUTE = "scoped-proxy";

   private static final String EXCLUDE_FILTER_ELEMENT = "exclude-filter";

   private static final String INCLUDE_FILTER_ELEMENT = "include-filter";

   private static final String FILTER_TYPE_ATTRIBUTE = "type";

   private static final String FILTER_EXPRESSION_ATTRIBUTE = "expression";


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

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

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

   protected void registerComponents(
         XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

      Object source = readerContext.extractSource(element);
      CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

      for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
         compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
      }

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

      readerContext.fireComponentRegistered(compositeDef);
   }

   protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
      if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
         BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy (
               element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,
               scanner.getResourceLoader().getClassLoader());
         scanner.setBeanNameGenerator (beanNameGenerator);
      }
   }

   protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
      // Register ScopeMetadataResolver if class name provided.
      if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {
         if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
            throw new IllegalArgumentException(
                  "Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
         }
         ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
               element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,
               scanner.getResourceLoader().getClassLoader());
         scanner.setScopeMetadataResolver(scopeMetadataResolver);
      }

      if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
         String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);
         if ("targetClass".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
         }
         else if ("interfaces".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
         }
         else if ("no".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.NO);
         }
         else {
            throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
         }
      }
   }

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

   @SuppressWarnings("unchecked")
   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);
      }
   }

   @SuppressWarnings("unchecked")
   private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
      Object result;
      try {
         result = classLoader.loadClass(className).newInstance();
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalArgumentException("Class [" + className + "] for strategy [" +
               strategyType.getName() + "] not found", ex);
      }
      catch (Exception ex) {
         throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
               strategyType.getName() + "]: a zero-argument constructor is required", ex);
      }

      if (!strategyType.isAssignableFrom(result.getClass())) {
         throw new IllegalArgumentException("Provided class name must be an implementation of " + strategyType);
      }
      return result;
   }

}

The doScan method of ClassPathBeanDefinitionScanner:

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;
}
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
   try {
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
            resolveBasePackage(basePackage) + "/" + this.resourcePattern;
      //The final path is: classpath*:com/test/servlet/**/*.class
      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;
}

 

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326928384&siteId=291194637