基于xml的Spring是如何解析@Component,@Service等注解的

发布时间 2023-12-03 13:36:39作者: 残城碎梦

Spring Framework2.0开始,引入可扩展的XML编程机制,该机制要求XML Schema命名空间需要与Handler建立映射关系。该关系配置在相对于classpath下的/META-INF/spring.handlers中。

如上图所示 ContextNamespaceHandler对应<context:...> 分析的入口。

ContextNamespaceHandler 

这些NameSpaceHandler是在什么时候实例化的呢?init()方法都是在什么时候调用的呢?

在AbstractApplicationContext的refresh()方法中,我们会调用一个obtainFreshBeanFactory()方法,源码如下:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

AbstractRefreshableApplicationContext#refreshBeanFactory中会调用所有AbstractRefreshableApplicationContext子类的loadBeanDefinitions()方法。

我们这里是XmlWebApplicationContext的loadBeanDefinitions方法。

一直跟踪代码,来到org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions,里面调用了org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions方法。

在createReaderContext(resource)中会创建NamespaceHandlerResolver接口的一个唯一实现类DefaultNamespaceHandlerResolver

回到documentReader.registerBeanDefinitions(doc, createReaderContext(resource));会调用org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 1.默认命名空间的处理
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        // 遍历root的子节点列表
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    // 1.1 默认命名空间节点的处理,例如: <bean id="test" class="" />
                    parseDefaultElement(ele, delegate);
                }
                else {
                    // 1.2 自定义命名空间节点的处理,例如:<context:component-scan/>、<aop:aspectj-autoproxy/>
                    delegate.parseCustomElement(ele);
                }
            }
        }
    } else {
        // 2.自定义命名空间的处理
        delegate.parseCustomElement(root);
    }
}

自定义命名空间节点的处理

public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    // 1.拿到节点ele的命名空间,例如常见的:
    // <context> 节点对应命名空间: http://www.springframework.org/schema/context
    // <aop> 节点对应命名空间: http://www.springframework.org/schema/aop
    String namespaceUri = getNamespaceURI(ele);
    // 2.拿到命名空间对应的的handler, 例如:http://www.springframework.org/schema/context 对应 ContextNameSpaceHandler
    // 2.1 getNamespaceHandlerResolver: 拿到namespaceHandlerResolver
    // 2.2 resolve: 使用namespaceHandlerResolver解析namespaceUri, 拿到namespaceUri对应的NamespaceHandler
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    // 3.使用拿到的handler解析节点(ParserContext用于存放解析需要的一些上下文信息)
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

拿到当时创建的 DefaultNamespaceHandlerResolver 对象,使用 DefaultNamespaceHandlerResolver 解析 namespaceUri,拿到对应的 handler。

ContextNamespaceHandler也就是在这时进行了init()方法初始化。

@Override
public NamespaceHandler resolve(String namespaceUri) {
    // 1.拿到配置文件的所有命名空间和对应的handler
    // 例如:"http://www.springframework.org/schema/aop" -> "org.springframework.aop.config.AopNamespaceHandler"
    Map<String, Object> handlerMappings = getHandlerMappings();
    // 2.拿到当前命名空间对应的handler (可能是handler的className,也可能是已经实例化的handler)
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        // 2.1 如果不存在namespaceUri对应的handler,则返回null
        return null;
    }
    else if (handlerOrClassName instanceof NamespaceHandler) {
        // 2.2 如果是已经实例化的handler,则直接强转返回
        return (NamespaceHandler) handlerOrClassName;
    }
    else {
        // 2.3 如果是handler的className
        String className = (String) handlerOrClassName;
        try {
            // 2.3.1 根据className,使用类加载器拿到该类
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            // 2.3.2 校验是否是继承自NamespaceHandler(所有的handler都继承自NamespaceHandler)
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            // 2.3.3 使用无参构造函数实例化handlerClass类
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            // 2.3.4 调用handler类的初始化方法(将命名空间下的节点名和对应的解析器注册到parsers缓存中)
            namespaceHandler.init();
            // 2.3.5 将实例化的handler放到缓存,替换原来的className
            // 原来为: namespaceUri -> handler的className,会被覆盖成: namespaceUri -> 实例化的handler
            handlerMappings.put(namespaceUri, namespaceHandler);
            // 返回实例化后的handler对象
            return namespaceHandler;
        }
        catch (ClassNotFoundException ex) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
                                         namespaceUri + "] not found", ex);
        }
        catch (LinkageError err) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
                                         namespaceUri + "]: problem with handler class file or dependent class", err);
        }
    }
}

使用拿到的 handler 解析 ele 节点。

org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse

public BeanDefinition parse(Element element, ParserContext parserContext) {
    // 1.findParserForElement: 给element寻找对应的BeanDefinition解析器
    // 2.使用BeanDefinition解析器解析element节点
    BeanDefinitionParser parser = findParserForElement(element, parserContext);
    return (parser != null ? parser.parse(element, parserContext) : null);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    // 1.1 拿到节点的localName,例如:annotation-config、component-scan
    String localName = parserContext.getDelegate().getLocalName(element);
    // 1.2 从parsers缓存中,拿到localName对应的解析器, 例如: component-scan -> ComponentScanBeanDefinitionParser
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
            "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }
    return parser;
}

ComponentScanBeanDefinitionParser

在上面我们拿到具体的BeanDefinitionParser解析器后就可以调用其parse方法进行解析了。

ClassPathBeanDefinitionScanner#doScan是扫描BeanDefinition并注册的实现 。

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

findCandidateComponents:从classPath扫描组件,并转换为备选BeanDefinition,也就是要做的解析@Component的核心方法。

findCandidateComponents在其父类ClassPathScanningCandidateComponentProvider 中。

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 {
        //将package转化为ClassLoader类资源搜索路径
        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)) {
                            //添加到返回结果的list
                            candidates.add(sbd);
                        }
                    }
                }
            }
        }
    }
    return candidates;
}

ClassPathScanningCandidateComponentProvider#isCandidateComponent其源码如下:

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    //省略部分代码
    for (TypeFilter tf : this.includeFilters) {
        if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}

includeFilters由registerDefaultFilters()设置初始值,有@Component,没有@Service啊?

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

Spring如何处理@Service的注解的呢?

其实@Component是任何Spring管理的组件的通用原型。@Repository、@Service和@Controller是派生自@Component。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @Service 派生自@Component
@Component
public @interface Service {

    /**
    * The value may indicate a suggestion for a logical component name,
    * to be turned into a Spring bean in case of an autodetected component.
    * @return the suggested component name, if any (or empty String otherwise)
    */
    @AliasFor(annotation = Component.class)
    String value() default "";

}

@Component是@Service的元注解,在读取@Service,也读取了它的元注解,并将@Service作为@Component处理。

AnnotationAttributesReadingVisitor#visitEnd()内部方法recursivelyCollectMetaAnnotations 递归的读取注解,与注解的元注解(读@Service,再读元注解@Component),并设置到metaAnnotationMap。

final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttributesVisitor {
    private final MultiValueMap<String, AnnotationAttributes> attributesMap;
    private final Map<String, Set<String>> metaAnnotationMap;

    public AnnotationAttributesReadingVisitor(String annotationType, MultiValueMap<String, AnnotationAttributes> attributesMap, Map<String, Set<String>> metaAnnotationMap, @Nullable ClassLoader classLoader) {
        super(annotationType, new AnnotationAttributes(annotationType, classLoader), classLoader);
        this.attributesMap = attributesMap;
        this.metaAnnotationMap = metaAnnotationMap;
    }

    public void visitEnd() {
        super.visitEnd();
        Class<?> annotationClass = this.attributes.annotationType();
        if (annotationClass != null) {
            List<AnnotationAttributes> attributeList = (List)this.attributesMap.get(this.annotationType);
            if (attributeList == null) {
                this.attributesMap.add(this.annotationType, this.attributes);
            } else {
                attributeList.add(0, this.attributes);
            }

            Set<Annotation> visited = new LinkedHashSet();
            Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass);
            if (!ObjectUtils.isEmpty(metaAnnotations)) {
                Annotation[] var5 = metaAnnotations;
                int var6 = metaAnnotations.length;

                for(int var7 = 0; var7 < var6; ++var7) {
                    Annotation metaAnnotation = var5[var7];
                    if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) {
                        this.recursivelyCollectMetaAnnotations(visited, metaAnnotation);
                    }
                }
            }

            Set<String> metaAnnotationTypeNames = new LinkedHashSet(visited.size());
            Iterator var10 = visited.iterator();

            while(var10.hasNext()) {
                Annotation ann = (Annotation)var10.next();
                metaAnnotationTypeNames.add(ann.annotationType().getName());
            }

            this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
        }

    }

    private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) {
        Class<? extends Annotation> annotationType = annotation.annotationType();
        String annotationName = annotationType.getName();
        if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName) && visited.add(annotation)) {
            try {
                if (Modifier.isPublic(annotationType.getModifiers())) {
                    this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true));
                }

                Annotation[] var5 = annotationType.getAnnotations();
                int var6 = var5.length;

                for(int var7 = 0; var7 < var6; ++var7) {
                    Annotation metaMetaAnnotation = var5[var7];
                    this.recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
                }
            } catch (Throwable var9) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Failed to introspect meta-annotations on [" + annotation + "]: " + var9);
                }
            }
        }

    }
}