美文网首页
Spring XML解析的详细过程 2

Spring XML解析的详细过程 2

作者: 农民工进城 | 来源:发表于2019-09-26 12:09 被阅读0次

    本章要点

    • 自定义节点的解析过程

    1.自定义节点的解析过程

    代码片段:

     <context:component-scan
            base-package="com.ailk" use-default-filters="false" name-generator="" 
            scope-resolver=" " scoped-proxy="no">
        <context:include-filter type="annotation"
                expression="org.springframework.stereotype.Service"> 
           </context:include-filter>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Controller"> 
           </context:exclude-filter>
    </context:component-scan>
    

    org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(Element)

        public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
            String namespaceUri = getNamespaceURI(ele);//1)
            if (namespaceUri == null) {
                return null;
            }
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);//2)
            if (handler == null) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
                return null;
            }
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }
    
    • 1)获取对应标签节点的namespace
      -2)获取相应的NamespaceHandlerResovler,具体信息是在META-INF/spring.handlers里配置的
      org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve(String)
    public NamespaceHandler resolve(String namespaceUri) {
            Map<String, Object> handlerMappings = getHandlerMappings();//1)
            Object handlerOrClassName = handlerMappings.get(namespaceUri);//2)
            if (handlerOrClassName == null) {
                return null;
            }
            else if (handlerOrClassName instanceof NamespaceHandler) {
                return (NamespaceHandler) handlerOrClassName;
            }
            else {
                String className = (String) handlerOrClassName;
                try {
                    Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);//3)
                    if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                        throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                                "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                    }
                    NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);//4)
                    namespaceHandler.init();//5)
                    handlerMappings.put(namespaceUri, namespaceHandler);//6)
                    return namespaceHandler;
                }
                catch (ClassNotFoundException ex) {
                    throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
                            "] for namespace [" + namespaceUri + "]", ex);
                }
                catch (LinkageError err) {
                    throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
                            className + "] for namespace [" + namespaceUri + "]", err);
                }
            }
        }
    

    -1)加载配置文件META-INF/spring.handlers
    -2)根据nanespace获取相应的handler字符串,例如:http://www.springframework.org/schema/context对应org.springframework.context.config.ContextNamespaceHandler

    • 3)、4)根据字符串反射实例化NamespaceHandler
      -5)调用NamespaceHandler的init()初始化方法,初始化一些对应标签的解析器
    • 6)将字符串替换成对应NamespaceHandler的实例类对象

    org.springframework.context.config.ContextNamespaceHandler.init()

    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());
        }
    
    }
    
    • 初始化一些标签对应的解析器
      org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(Element, ParserContext)
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            BeanDefinitionParser parser = findParserForElement(element, parserContext);
            return (parser != null ? parser.parse(element, parserContext) : null);
        }
    

    org.springframework.beans.factory.xml.NamespaceHandlerSupport.findParserForElement(Element, ParserContext)

        private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
            String localName = parserContext.getDelegate().getLocalName(element);//1)
            BeanDefinitionParser parser = this.parsers.get(localName);//2)
            if (parser == null) {
                parserContext.getReaderContext().fatal(
                        "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
            }
            return parser;
        }
    
      1. 获取localname,例如context:component-scan:得到的就是component-scan
    • 2)根据localname获取相应的解析器,例如:component-scan获取的就是org.springframework.context.annotation.ComponentScanBeanDefinitionParser

    org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(Element, ParserContext)

        public BeanDefinition parse(Element element, ParserContext parserContext) {
            String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);//1)获取base-package
            basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);//2)
            String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);//3)
    
            ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);//4)
            Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);//5)
            registerComponents(parserContext.getReaderContext(), beanDefinitions, element);//6)
    
            return null;
        }
    
    • 1)获取context标签对应的base-package属性
    • 2)如果有环境变量,则替换掉环境变量
    • 3)可以配置多个包路径,以逗号“,”或分号“;”隔开
    • 4)配置扫描器
    • 5)进行扫描出所配置包下,所有的BeanDefinition,并注册到map中
    • 6)激活componentRegistered事件

    org.springframework.context.annotation.ComponentScanBeanDefinitionParser.configureScanner(ParserContext, Element)

        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));//1)
            }
    
            ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);//2)
            scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());//3)
            scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());//4)
    
            if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
                scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
            }
    
            try {
                parseBeanNameGenerator(element, scanner);//5)设置名字生成器
            }
            catch (Exception ex) {
                parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
            }
    
            try {
                parseScope(element, scanner);//6)
            }
            catch (Exception ex) {
                parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
            }
    
            parseTypeFilters(element, scanner, parserContext);//7)
    
            return scanner;
        }
    
    
    • 1)获取use-default-filters的属性值
    • 2)创建ClassPathBeanDefinitionScanner实例对象
    • 3)设置一些默认值
    • 4)获取beans标签下的default-autowire-candidates属性
    • 5)设置beanname生成器,通过name-generator标签配置
    • 6)解析scope-resolver和scoped-proxy 标签,并设置scanner对应的属性
    • 6)解析filter配置,并添加到scanner属性中

    org.springframework.context.annotation.ComponentScanBeanDefinitionParser.createScanner(XmlReaderContext, boolean)

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

    org.springframework.context.annotation.ClassPathBeanDefinitionScanner.ClassPathBeanDefinitionScanner(BeanDefinitionRegistry, boolean, Environment, ResourceLoader)

        public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
                Environment environment, @Nullable ResourceLoader resourceLoader) {
    
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
            this.registry = registry;
    
            if (useDefaultFilters) {
                registerDefaultFilters();//1)
            }
            setEnvironment(environment);
            setResourceLoader(resourceLoader);
        }
    
    • 1)默认的支持扫描的注解,主要包括org.springframework.stereotype.Component、javax.annotation.ManagedBean、javax.inject.Named
    • 2)设置环境变量
    • 3)设置加载器

    org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parseTypeFilters(Element, ClassPathBeanDefinitionScanner, ParserContext)

        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);//1)
                        }
                        else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
                            TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                            scanner.addExcludeFilter(typeFilter);//2)
                        }
                    }
                    catch (ClassNotFoundException ex) {
                        parserContext.getReaderContext().warning(
                                "Ignoring non-present type filter class: " + ex, parserContext.extractSource(element));
                    }
                    catch (Exception ex) {
                        parserContext.getReaderContext().error(
                                ex.getMessage(), parserContext.extractSource(element), ex.getCause());
                    }
                }
            }
        }
    
    • 1)解析include-filter
    • 2)解析exclude-filter

    org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String...)

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
            for (String basePackage : basePackages) {
                Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//1)拿到该包下所有的符合条件的Class
                for (BeanDefinition candidate : candidates) {
                    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);//2)
                    candidate.setScope(scopeMetadata.getScopeName());
                    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//3)
                    if (candidate instanceof AbstractBeanDefinition) {
                        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);//4)
                    }
                    if (candidate instanceof AnnotatedBeanDefinition) {
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);//5)
                    }
                    if (checkCandidate(beanName, candidate)) {//6)
                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                        definitionHolder =
                                AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//7)
                        beanDefinitions.add(definitionHolder);
                        registerBeanDefinition(definitionHolder, this.registry);//7)
                    }
                }
            }
            return beanDefinitions;
        }
    
    • 1)拿到该包下所有的符合条件的Class
    • 2)解析 scope-resolver和scoped-proxy
    • 3)生成beanName
    • 4)设置一些默认值
    • 5)解析一些注解,例如@DependsOn@Role
    • 6)检查名字是否唯一,缓存中org.springframework.beans.factory.support.DefaultListableBeanFactory.beanDefinitionMap是否已经存在
    • 7)注册到缓存map中

    org.springframework.context.annotation.AnnotationBeanNameGenerator.generateBeanName(BeanDefinition, BeanDefinitionRegistry)

        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
            if (definition instanceof AnnotatedBeanDefinition) {
                String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);//1)
                if (StringUtils.hasText(beanName)) {
                    return beanName;
                }
            }
            return buildDefaultBeanName(definition, registry);//2)
        }
    
    • 1)获取注解上是否指定了bean名称
    • 2)生成默认名称,类名首字母小写

    org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(String)

        public Set<BeanDefinition> findCandidateComponents(String basePackage) {
            if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
                return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
            }
            else {
                return scanCandidateComponents(basePackage);
            }
        }
    

    org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(String)

    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
            Set<BeanDefinition> candidates = new LinkedHashSet<>();
            try {
                String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                        resolveBasePackage(basePackage) + '/' + this.resourcePattern;//1)
                Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);//2)
                boolean traceEnabled = logger.isTraceEnabled();
                boolean debugEnabled = logger.isDebugEnabled();
                for (Resource resource : resources) {
                    if (traceEnabled) {
                        logger.trace("Scanning " + resource);
                    }
                    if (resource.isReadable()) {
                        try {
                            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);//2)
                            if (isCandidateComponent(metadataReader)) {//3)
                                ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                                sbd.setResource(resource);
                                sbd.setSource(resource);
                                if (isCandidateComponent(sbd)) {//4)
                                    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;
        }
    
    
    • 1)将包名替换成路径名
    • 2)根据class的Resource生成MetadataReader,读取Class字节流封装到ClassReader中,然后并对MetadataReader进行缓存,放到 org.springframework.core.type.classreading.CachingMetadataReaderFactory.metadataReaderCache
    • 3)匹配filter,看看是否匹配include-filterexclude-filter
    • 4)是否是独立类(非内部类),具体的类(非接口、和抽象类)或是抽象类带有Lookup注解
      具体代码如下:
        protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
            AnnotationMetadata metadata = beanDefinition.getMetadata();
            return (metadata.isIndependent() && (metadata.isConcrete() ||
                    (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
        }
    

    org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(String)

        public Resource[] getResources(String locationPattern) throws IOException {
            Assert.notNull(locationPattern, "Location pattern must not be null");
            if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
                if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
                    return findPathMatchingResources(locationPattern);
                }
                else {
                    return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
                }
            }
            else {
                int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
                        locationPattern.indexOf(':') + 1);
                if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
                    return findPathMatchingResources(locationPattern);
                }
                else {
                    return new Resource[] {getResourceLoader().getResource(locationPattern)};
                }
            }
        }
    
    • 获取Class文件封装为Resource

    相关文章

      网友评论

          本文标题:Spring XML解析的详细过程 2

          本文链接:https://www.haomeiwen.com/subject/yxfuyctx.html