Spring源码解析-自定义标签解析和SPI机制-3

Posted 进击的萝卜头

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码解析-自定义标签解析和SPI机制-3相关的知识,希望对你有一定的参考价值。

1. 涉及SPI机制地方

  1. 自定义标签:例如:context aop 等等都是自定义标签,需要利用SPI机制
  2. 默认标签中的自定义元素加载也涉及到SPI机制

2. SPI机制:

SPI就是一个服务的扩展机制,可以把接口的实现类配置到META-INF元数据区,框架启动时加载到缓存,最初的版本是jdk中实现的,后来在spring、springboot、dubbo中都有相应的使用。

3. JDK的SPI机制:

META-INF下创建services目录,然后以接口全限定名为文件名,将实现类的全限定名放进去,这样运行程序时,会加载实现类的名称进jvm,调用的时候会调用newInstance()方法实例化对象。

示例:

  • 创建一个IAnimal接口:
package com.hello.spi;
 
public interface IAnimal {
    void sing();
}
  • 创建两个实现类:
package com.hello.spi;
 
public class Cat implements IAnimal {
    @Override
    public void sing() {
        System.out.println("cat sing......");
    }
}
package com.hello.spi;
 
public class Dog implements IAnimal {
    @Override
    public void sing() {
        System.out.println("dog sing......");
    }
}
//全路径需和类路径保持一致
resource\\META-INF.services\\com.hello.spi.IAnimal
//此路径文件下有
com.hello.spi.Cat
com.hello.spi.Dog
  • 测试代码:
public class TestSPI {
    public static void main(String[] args) {
        ServiceLoader<IAnimal> animals = ServiceLoader.load(IAnimal.class);
        for (Iterator<IAnimal> iter = animals.iterator();iter.hasNext();) {
            IAnimal animal = iter.next();
            animal.sing();
        }
    }
}

5. spring的spi机制:

  • 获取spring中所有jar包里面的"META-INF/spring.handlers"文件,并且建立映射关系
  • spring的类DefaultNamespaceHandlerResolver这个类,会懒加载spring.handler文件内配置的实现类进内存
  • 读取META-INF/spring.handlers目录下的实现类进jvm
  • 然后缓存到handlerMappings,等待后面使用
  • 这个是spring-context工程下spring.handlers文件内容: key为命名空间url、value为类的全限定名,加载完成后会缓存到handlerMappings中
//此方法上一篇中有提到
    private Map<String, Object> getHandlerMappings() {
       Map<String, Object> handlerMappings = this.handlerMappings;
       if (handlerMappings == null) {
          synchronized (this) {
             handlerMappings = this.handlerMappings;
             if (handlerMappings == null) {
                if (logger.isTraceEnabled()) {
                   logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
                }
                try {
                   //加载"META-INF/spring.handlers"文件过程
                   Properties mappings =
                         PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                   if (logger.isTraceEnabled()) {
                      logger.trace("Loaded NamespaceHandler mappings: " + mappings);
                   }
    
                   //所有"META-INF/spring.handlers"文件里面的内容建立映射关系
                   handlerMappings = new ConcurrentHashMap<>(mappings.size());
                   CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                   this.handlerMappings = handlerMappings;
                }
                catch (IOException ex) {
                   throw new IllegalStateException(
                         "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
             }
          }
       }
       return handlerMappings;
    }

6. 自定义标签的解析

6.1 解析自定义元素

    public BeanDefinition parseCustomElement(Element ele) {
        return parseCustomElement(ele, null);
    }

    public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
        // 解析到自定义元素的命名空间,例如:context元素命名空间  http://www.springframework.org/schema/context
        String namespaceUri = getNamespaceURI(ele);
        if (namespaceUri == null) {
            return null;
        }
        // 根据url找命名空间handler
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        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));
    }

6.2 寻找命名空间对象(此方法上一章有用到)

    public NamespaceHandler resolve(String namespaceUri) {
        //获取spring中所有jar包里面的 "META-INF/spring.handlers"文件,并且建立映射关系
        Map<String, Object> handlerMappings = getHandlerMappings();

        //根据namespaceUri:http://www.springframework.org/schema/p,获取到这个命名空间的处理类
        // 根据url找到对应的全限定类名
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        }
        //如果时对象直接返回,说明不是第一次使用
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        // 首次调用,会走下述逻辑
        // 1.根据类名加载此类,创建class对象
        // 2.根据class反射创建对象
        // 3.初始化init
        // 4.放入缓存
        // 5.返回这个对象
        else {
            String className = (String) handlerOrClassName;
            try {
                //反射出来类
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                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);

                //调用处理类的init方法,在init方法中完成标签元素解析类的注册***重要
                namespaceHandler.init();
                handlerMappings.put(namespaceUri, namespaceHandler);
                return namespaceHandler;
            }
            // catch略......
        }
    }

6.3 初始化,把属性和解析器缓存映射,主要的处理缓存逻辑都在父类NamespaceHandlerSupport中, 这样初始化之后,这个NamespaceHandler就包含了众多解析器。

    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());
        }
    
    }
    
    //NamespaceHandlerSupport类中
    protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
        this.parsers.put(elementName, parser);
    }

6.4 跳回到6.1拿到NamespaceHandler,开始解析

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        BeanDefinitionParser parser = findParserForElement(element, parserContext);
        return (parser != null ? parser.parse(element, parserContext) : null);
    }
        
    private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        String localName = parserContext.getDelegate().getLocalName(element);
        //从缓存中拿到component-scan的解析器
        BeanDefinitionParser parser = this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal(
                    "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        }
        return parser;
    }

6.5 拿到解析器,跳转至ComponentScanBeanDefinitionParser,开始解析

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

6.6 创建一个扫描器

    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.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,
                readerContext.getEnvironment(), readerContext.getResourceLoader());
    }
    
    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();
        }
        setEnvironment(environment);
        setResourceLoader(resourceLoader);
    }

6.7 注册过滤器,支持注解扫描

    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.trace("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.trace("JSR-330 \'javax.inject.Named\' annotation found and supported for component scanning");
        }
        catch (ClassNotFoundException ex) {
            // JSR-330 API not available - simply skip.
        }
    }

6.8 跳回到6.5,创建扫描器完成后,就可以扫描basePackages包了

    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);

    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) {
            // 寻找符合条件的类,有Component注解的
            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);
                    //把BeanDefinition注册到spring的缓存中
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

6.9 寻找符合条件的类

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            //看此方法
            return scanCandidateComponents(basePackage);
        }
    }
    
    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + \'/\' + this.resourcePattern;
            //这里递归寻找文件*****重要
            Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().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, getMetadataReaderFactory())) {
                return false;
            }
        }
        //包含的组件
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, getMetadataReaderFactory())) {
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

6.10 跳回6.7查看注册器过滤器类型AnnotationTypeFilter,其父类AbstractTypeHierarchyTraversingFilter

    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;
        }
        ClassMetadata metadata = metadataReader.getClassMetadata();
        if (matchClassName(metadata.getClassName())) {
            return true;
        }

        if (this.considerInherited) {
            String superClassName = metadata.getSuperClassName();
            if (superClassName != null) {
                // Optimization to avoid creating ClassReader for super class.
                Boolean superClassMatch = matchSuperClass(superClassName);
                if (superClassMatch != null) {
                    if (superClassMatch.booleanValue()) {
                        return true;
                    }
                }
                else {
                    // Need to read super class to determine a match...
                    try {
                        if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
                            return true;
                        }
                    }
                    catch (IOException ex) {
                        logger.debug("Could not read super class [" + metadata.getSuperClassName() +
                                "] of type-filtered class [" + metadata.getClassName() + "]");
                    }
                }
            }
        }

        if (this.considerInterfaces) {
            for (String ifc : metadata.getInterfaceNames()) {
                // Optimization to avoid creating ClassReader for super class
                Boolean interfaceMatch = matchInterface(ifc);
                if (interfaceMatch != null) {
                    if (interfaceMatch.booleanValue()) {
                        return true;
                    }
                }
                else {
                    // Need to read interface to determine a match...
                    try {
                        if (match(ifc, metadataReaderFactory)) {
                            return true;
                        }
                    }
                    catch (IOException ex) {
                        logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
                                metadata.getClassName() + "]");
                    }
                }
            }
        }

        return false;
    }

6.11 跳转回子类进行判断

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

6.12 跳转回6.9,如果发现这个类上面有Component注解信息,那么就符合条件。对于符合条件的,就会创建一个beanDefinition对象,然后将元数据信息封装进去,并放入容器中,最后返回

6.13 跳回6.8,拿到candidates后,就会遍历处理,返回beanDefinition集合,结合6.5,然后将beanDefinition集合注册到spring容器中,这样这个context的自定义标签解析完毕。

<!--配置扫描路径样例-->
<context:component-scan base-package="com.hello" />

总结

  • 上面是以context:component-scan这个自定义标签为例,分析了解析的流程,大概流程如下:
  • 获取元素命名空间url ,nameSpaceUrl
  • 根据namespaceUrl找到nameSpaceHandler,这个使用到了spi懒加载机制(初次获取会反射创建handler对象,然后缓存)
  • 创建handler后,会init初始化,初始化的过程中会缓存各种解析器
  • 根据元素的localname,查询到解析器,然后调用解析器的parse方法开始解析
  • 无论是默认标签还是自定义标签,它们最终都是生成beanDefinition对象,然后注册到beanDefinitionMaps中缓存。

以上是关于Spring源码解析-自定义标签解析和SPI机制-3的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码解析——自定义标签解析

8Spring 源码学习 ~ 自定义标签的解析

Spring源码学习自定义标签的解析

Spring 源码分析--自定义标签的解析

Spring 源码分析--自定义标签的使用

6.2 dubbo在spring中自定义xml标签源码解析