Spring Bean加载探究(二)

上文说到在解析具体的bean时候,会走到不同的分支,可能是parseDefaultElement,也可能是parseCustomElement,接下来看parseCustomElement的加载机制.

自定义标签

  • 自定义标签的使用方法(参考)
  • 创建一个POJO对象,
  • 创建一个xsd文件描述组件内容, 注意在xsd文件中描述新的namespace( what's xsd)
  • 创建一个类实现BeanDefinitioParser接口
  • 创建一个hanlder文件, 该类实现了NameSpaceHanlderSupport接口, 目的是将组件注册到Spring容器中
  • 编写Spring.handlers 和 Spring.schema 文件, 这两个文件分别是注册hanlder类的所在包名以及xsd文件所在的位置
  • 详解自定义标签的解析步骤(事无巨细)
  • 获得node所在的namespace, 例如对于context:property-placeholder, 得到的namespace是http://www.springframework.org/schema/context
  • 获得NamespaceHandler
    1. 获得handlerMappings
private Map getHandlerMappings() {
        if(this.handlerMappings == null) {
            synchronized(this) {
                if(this.handlerMappings == null) {
                    try {
                        // 在此处先进行校验, 如果当前的handlerMappings为空,则从hanlderMappingsLocation中读取文件, 然后再把k,v写到mapper中
                        Properties ex = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if(this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + ex);
                        }

                        ConcurrentHashMap handlerMappings = new ConcurrentHashMap(ex.size());
                        CollectionUtils.mergePropertiesIntoMap(ex, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        }

        return this.handlerMappings;
    }
  1. 根据namespace拿到hanlderOrClassName
    2.1 由于加载器不一定是bean, 所以可能尚未加载, hanlderOrClassName可能是对象也可能是class name, 如果是class name, 则还需要加载类并且初始化
public NamespaceHandler resolve(String namespaceUri) {
        Map handlerMappings = this.getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if(handlerOrClassName == null) {
            return null;
        } else if(handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;

            try {
                Class err = ClassUtils.forName(className, this.classLoader);
                if(!NamespaceHandler.class.isAssignableFrom(err)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                } else {
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(err); // 初始化bean对象
                    namespaceHandler.init();
                    handlerMappings.put(namespaceUri, namespaceHandler);
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
            }
        }
    }
  • 解析自定义标签
    1. findParserForElement
      1.1 使用delegategetLocalName
      1.2 拿到BeanDefinitioParser, (根据上文的nameSpaceSupport中的实现, 可以知道是如何实现的)
    2. parse函数
      2.1 调用parseInternal函数拿到bean definition
      2.2 解析id
      2.3 获得alias
      2.4 根据definition, id, aliases构建一个BeandefinitionHolder, 并且注册到context中
    3. 在parseInternal函数中执行了什么逻辑?
      3.1 判断在beanParser中是不是重写了getBeanClass函数
      3.2 判断在beanParser中是不是重写了getBeanClassName
      3.3 可能会复用父类的scope等属性
      3.4 调用自定义的beanParser的doParse函数

你可能感兴趣的:(Spring Bean加载探究(二))