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.Catcom.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中缓存。