Spring源码解析(一)

Spring

  • spring是一个装载bean,调度bean的容器

(一)spring的xml加载

这部分是spring载入了resource中的xml配置,并使用了对应的解析器,然后开始进行默认部分标签解析部分的源码。
简单说一下xml,个人理解为一种通过标签格式化表示结构层次的方式,有两种格式,DTD和XSD,不深究,区分很好区分

这种头TM是DTD
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
这种头TM是XSD
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

然后我们开始看载入xml的关键bean—XmlBeanFactory

//有这样一个构造方法,reader是定义的XmlBeanDefinitionReader
//这里简单讲就是通过XmlBeanDefinitionReader载入Xml资源。
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }

Resource这个接口很简单,首先判断这个资源是否存在,是否可读,是否开放,传入的资源支持URL,URI,File三种形式,
进入loadBeanDefinitions(resource)方法中,我们看到如下

@Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        //这个EncodedResource的作用是当资源需要以固定编码格式传入时生效。
        return loadBeanDefinitions(new EncodedResource(resource));
    }

继续跟进,之后我只会截取一些关键代码。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    ···
    try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //前面是对应将资源引入,关键的一步,将resource进行载入beanDefinition
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
    ···
}

继续跟进,看spring将载入的资源做了些什么

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //原来只做了两步,1:将资源装载到Document对象中
            Document doc = doLoadDocument(inputSource, resource);
            //2:将资源注册到beanDefinition中。
            return registerBeanDefinitions(doc, resource);
        }
    ····
    ····
    ····
}

接着往下看这个doLoadDocument方法中,有一个参数叫EntityResolver,这个解析器是干嘛用的呢,他有很多的实现类,其中有一个叫DelegatingEntityResolver的实现类是用来委派到底由哪个实现类解析器真正解析的,然后去实现真正的实现类,判断的方法如下。

public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId != null) {
            if (systemId.endsWith(DTD_SUFFIX)) {
                return this.dtdResolver.resolveEntity(publicId, systemId);
            }
            else if (systemId.endsWith(XSD_SUFFIX)) {
                return this.schemaResolver.resolveEntity(publicId, systemId);
            }
        }
        return null;
    }

传入了publicId和systemId,
根据if (systemId != null && systemId.endsWith(DTD_EXTENSION))

if (systemId != null) {
            String resourceLocation = getSchemaMappings().get(systemId);
            if (resourceLocation != null) {
                Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
                try {
                    InputSource source = new InputSource(resource.getInputStream());
                    source.setPublicId(publicId);
                    source.setSystemId(systemId);
                    ····
                    ····
                    ····

返回对应的解析器,validationMode是校验xml的就不细说了。

Document loadDocument(
            InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
            throws Exception;

这时候我们已经返回了由解析器解析XML出来的所有标签,并将这些标签的属性对应的封装在Document对象中了。
然后我们来看最关键逻辑registerBeanDefinitions(doc, resource);

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //创建一个读取Document的Bean的属性定义的类(单一职责)。
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //主要逻辑,注册BeanDefinitions
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        //返回注册的数目
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

接着往下看,

protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        //创建一个BeanDefinition的翻译委托器
        this.delegate = createDelegate(getReaderContext(), root, parent);
        //这里有一个属性叫做profile,是在beans标签中可以配置载入的环境为dev或者product或者测试。
        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    return;
                }
            }
        }
        //模板模式,为了扩展前
        preProcessXml(root);
        //主要逻辑
        parseBeanDefinitions(root, this.delegate);
        //模板模式,为了扩展后
        postProcessXml(root);

        this.delegate = parent;
    }

继续向下:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            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)) {
                    //默认的标签解析
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                    //自定义标签解析
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

默认部分标签的解析

//进行了4种标签的解析,从bean标签也就是最核心的标签开始。

* bean标签的解析


private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

简单分析一下这个processBeanDefinition(ele,delegate)方法。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //创建一个beanDefinition的持有类
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            //对自定义的一些属性进行装饰
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
            //将这个持有类所持有的BeanDefinition属性注册到那个final的Map中。    
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            //将这种注册成功的事件通过监听器发送给对应的那些想要监听的东西。
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

其实这里简单说一下这个BeanDefinition这个类,他是一个与你在XML中所写的<bean>标签格式一一对应的一个类,如果我这句话说的不好理解,那你之后的一小部分是不需要看的,你就认为spring替你将<bean>标签内的所有属性都封装成了BeanDefinition这个类,你使用的时候就直接调用就行了。废话不说了,接着向下看

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //提取bean的id属性
        String id = ele.getAttribute(ID_ATTRIBUTE);
        //提取bean的name属性
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        //bean的别名
        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        //这部分逻辑是如果重复,就覆盖。不重要。
        ····
        ····
        ····
        //这就是具体提取bean标签中属性的类,我们单拿出去看
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        //这一段是检测bean有没有指定beanname,如果没有就使用默认规则生成beanName
        ····
        ····
        ····
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            //把提取类和别名,beanName放入beanDefinition的持有类,返回这个持有类
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

解释下AbstractBeanDefinition

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
            //创建BeanDefinition对象,这个create默认使用的是GenericBeanDefinition,这个类是spring2.5以后添加的实现,属于一站式服务。
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            //将默认的属性,比如是否是单例,是否是原型之类的属性放入BeanDefinition
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //这里将Description标签解析出来
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //解析元数据标签,解析lookup,解析ReplacedMethod,这三个方法打开后是大同小异的,所以放在一起说了,
            //他们唯一的区别if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT))
            //就是上面那句判断到底是什么模式的node节点信息,然后进行对应的提取处理,放到属性map中。
            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            //重点说一下这个constructor,点开方法后你会发现,提取出了index,type,name三个属性,
            //根据index的不同,选择了两种存储模式,addIndexedArgumentValue和addGenericArgumentValue
            //index的模式存储在一个LinkedHashMap<Integer, ValueHolder>,
            //而非index的模式存储在一个LinkedList<ValueHolder>中。这是最大的不同
            parseConstructorArgElements(ele, bd);
            //几乎同上
            parsePropertyElements(ele, bd);
            //放入final LinkedHashMap<String, AutowireCandidateQualifier>中。
            parseQualifierElements(ele, bd);


            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

至此,默认的属性我们已经全部解析完毕,并且封装到了BeanDefinition中,然后将beanDefinition连同他的beanname,alias[],一起放入了BeanDefinitionHolder中,返回。然后我们进行对自定义标签装饰。

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
            Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

        BeanDefinitionHolder finalDefinition = definitionHolder;

        // Decorate based on custom attributes first.
        NamedNodeMap attributes = ele.getAttributes();
        //进行判断,跳过自己的默认的属性,查找是否有值得装饰的自定义的属性标签并装饰。
        for (int i = 0; i < attributes.getLength(); i++) {
            Node node = attributes.item(i);
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }

        // 装饰那些自标签中那些需要装饰的标签。
        NodeList children = ele.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
            }
        }
        return finalDefinition;
    }

具体的判断逻辑在此实现,是通过命名空间来判断的。

public BeanDefinitionHolder decorateIfRequired(
            Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {

        String namespaceUri = getNamespaceURI(node);
        //关键判断语句。
        if (!isDefaultNamespace(namespaceUri)) {
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler != null) {
                return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
            }
            else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            }
            else {
                // A custom namespace, not to be handled by Spring - maybe "xml:...".
                if (logger.isDebugEnabled()) {
                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
                }
            }
        }
        return originalDef;
    }

至此,你的持有类已经获取了所有应该注册的属性了,之后我们需要将这些属性注册到那个map中,以beanname作为key,spring也是这么做的,但是还做了一些其他工作。
首先注册有beanName注册,还有alias注册两种方式。
注册前会有最后一次校验,是对方法是否能覆盖进行校验,

public void validate() throws BeanDefinitionValidationException {
        if (!getMethodOverrides().isEmpty() && getFactoryMethodName() != null) {
            throw new BeanDefinitionValidationException(
                    "Cannot combine static factory method with method overrides: " +
                    "the static factory method must create the instance");
        }

        if (hasBeanClass()) {
            prepareMethodOverrides();
        }
    }

对beanname被注册了的处理,如果不允许覆盖,抛异常,否则覆盖。

if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }

加入map缓存
synchronized (this.beanDefinitionMap),这个涉及到多线程,所以搞了一个锁。
清除解析前留下的对应的beanName缓存。
别名注册与beanName注册差不多。

然后是推送监听器消息,这个在spring中没实现。

  • 2 Alias标签的解析
protected void processAliasRegistration(Element ele) {
        String name = ele.getAttribute(NAME_ATTRIBUTE);
        String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
        boolean valid = true;
        if (!StringUtils.hasText(name)) {
            getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }
        if (!StringUtils.hasText(alias)) {
            getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }
        if (valid) {
            try {
                getReaderContext().getRegistry().registerAlias(name, alias);
            }
            catch (Exception ex) {
                getReaderContext().error("Failed to register alias '" + alias +
                        "' for bean with name '" + name + "'", ele, ex);
            }
            getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
        }
    }

和bean标签的注册是一样的

  • 3 import的标签解析。
    简单说:import标签用于模块的划分
    重要的就是资源的定位。
protected void importBeanDefinitionResource(Element ele) {
        //获取地址
        String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
        if (!StringUtils.hasText(location)) {
            getReaderContext().error("Resource location must not be empty", ele);
            return;
        }
        //获取系统格式
        // Resolve system properties: e.g. "${user.dir}"
        location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

        Set<Resource> actualResources = new LinkedHashSet<Resource>(4);
        //判定是绝对路径还是相对路径。
        // Discover whether the location is an absolute or relative URI
        boolean absoluteLocation = false;
        try {
            absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
        }
        catch (URISyntaxException ex) {
            // cannot convert to an URI, considering the location relative
            // unless it is the well-known Spring prefix "classpath*:"
        }

        // 如果是绝对路径则递归调用解析bean
        // Absolute or relative?
        if (absoluteLocation) {
            try {
                int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                if (logger.isDebugEnabled()) {
                    logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                }
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error(
                        "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
            }
        }
        else {
            //相对路径则计算处绝对路径然后再次递归调用解析。
            // No URL -> considering resource location as relative to the current file.
            try {
                int importCount;
                Resource relativeResource = getReaderContext().getResource().createRelative(location);
                if (relativeResource.exists()) {
                    importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                    actualResources.add(relativeResource);
                }
                else {
                    String baseLocation = getReaderContext().getResource().getURL().toString();
                    importCount = getReaderContext().getReader().loadBeanDefinitions(
                            StringUtils.applyRelativePath(baseLocation, location), actualResources);
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                }
            }
            catch (IOException ex) {
                getReaderContext().error("Failed to resolve current resource location", ele, ex);
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
                        ele, ex);
            }
        }
        //递归注册结束后将路径放到数组中,然后通知监听器注册结束
        Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
        getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
    }

之后最后一个,解析beans标签。
无非就是递归解析beans,没有任何的差别。
以上就是Spring对默认的标签解析形式。

解析自定义部分的标签

光有默认标签很多时候满足不了我们的需求,这时候我们就会去解析自定义标签。
之后以spring-aop为例,我们去解析一下自定义标签的顺序。

使用自定义标签分四步,
1:创建自定义类POJO来接受配置文件
2:创建一个xsd文件描述组件及元素内容。
3:创建一个文件,实现BeanDefinitionParser接口。主要是其中的Parse方法
4:创建一个Handler文件,继承NamespaceHandlerSupport,重写其init方法,将之前实现的翻译器注册到HashMap<String, BeanDefinitionParser>中。

那么接下来就开始解析spring-aop标签的秘密
首先Spring将我们写的xml,带aop标签的那种,加载到Resource中。

//之前解析默认标签时我们是从这里开始的,那么自定义标签也从这里开始
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //这里由于我们获取到的不是默认的命名空间了,所以,跳转到解析自定义标签
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            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)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        //也就是这里
        else {
            delegate.parseCustomElement(root);
        }
    }

向下看去,这个parseCustomElement方法

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //首先获取命名空间
        String namespaceUri = getNamespaceURI(ele);
        //根据命名空间寻找对应的控制器
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        //解析返回BeanDefinition
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

其实看起来和普通的标签是一样的,你没想错,其实。。。。就是一样的。
在获取命名空间这个方法中已经由w3c给我们实现了获取URI的方法。我们从之前加载进来的xml中获取到了spring-aop的命名空间。http://www.springframework.org/schema/aop
通过这个命名空间,去DefaultNamespaceHandlerResolver中调用其resolve(uri)方法,来获取handler,具体实现代码如下。

public NamespaceHandler resolve(String namespaceUri) {

        Map<String, Object> handlerMappings = getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);

这个getHandlerMappings就是去加载我们前面提到的Spring.handlers文件,这个文件默认的location就定义在这个方法中,是META/INF文件夹下,所以,如图
这里写图片描述
通过这个资源,我们就能定位其handler的具体实现
这里写图片描述
接着向下看,


        if (handlerOrClassName == null) {
            return null;
        }
        //这步的逻辑是如果缓存Map中有这个handler类,则取出,
        else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler) handlerOrClassName;
        }
        //如果没有就去通过反射生成,然后将反射生成的handler存在缓存中,然后返回,
        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);
                namespaceHandler.init();
                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类,我们打开看看,原来他进行了init将所有的parser注册到了map中

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}

接下来,我们也获得了handler,那么就该进行handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))

@Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        return findParserForElement(element, parserContext).parse(element, parserContext);
    }

点开parse的逻辑

public final BeanDefinition parse(Element element, ParserContext parserContext) {
        //获取definition,就是将一些什么懒加载啊,是否嵌套啊,一些东西先解析出来,然后去解析你自定义的那个parse
        AbstractBeanDefinition definition = parseInternal(element, parserContext);
        if (definition != null && !parserContext.isNested()) {
            try {
                String id = resolveId(element, definition, parserContext);
                if (!StringUtils.hasText(id)) {
                    parserContext.getReaderContext().error(
                            "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
                                    + "' when used as a top-level tag", element);
                }
                String[] aliases = null;
                if (shouldParseNameAsAliases()) {
                    String name = element.getAttribute(NAME_ATTRIBUTE);
                    if (StringUtils.hasLength(name)) {
                        aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                    }
                }
                //大家熟悉的BeanDefinition持有器
                BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
                //注册holder
                registerBeanDefinition(holder, parserContext.getRegistry());
                //通知监听器,熟悉的四步走
                if (shouldFireEvents()) {
                    BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
                    postProcessComponentDefinition(componentDefinition);
                    parserContext.registerComponent(componentDefinition);
                }
            }
            catch (BeanDefinitionStoreException ex) {
                parserContext.getReaderContext().error(ex.getMessage(), element);
                return null;
            }
        }
        return definition;
    }

以aop的config为例,以下是将你定义在Spring.schema中的xsd文件中的标签一一解析出来的逻辑。

public BeanDefinition parse(Element element, ParserContext parserContext) {
        CompositeComponentDefinition compositeDef =
                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
        parserContext.pushContainingComponent(compositeDef);

        configureAutoProxyCreator(parserContext, element);

        List<Element> childElts = DomUtils.getChildElements(element);
        for (Element elt: childElts) {
            String localName = parserContext.getDelegate().getLocalName(elt);
            if (POINTCUT.equals(localName)) {
                parsePointcut(elt, parserContext);
            }
            else if (ADVISOR.equals(localName)) {
                parseAdvisor(elt, parserContext);
            }
            else if (ASPECT.equals(localName)) {
                parseAspect(elt, parserContext);
            }
        }

        parserContext.popAndRegisterContainingComponent();
        return null;
    }

以上就是spring对自定义标签的解析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值