美文网首页
Spring源码之loadbeandefinition

Spring源码之loadbeandefinition

作者: 小生_chen | 来源:发表于2018-10-21 18:54 被阅读0次

    首先我们知道spring的启动入口在web.xml里面的一个监听器里

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

    然后我们找到它的启动方法

    public void contextInitialized(ServletContextEvent event) {
            initWebApplicationContext(event.getServletContext());
    }
    

    里面有一个configureAndRefreshWebApplicationContext()方法代表着启动和刷新容器,我们看到最后一行wac.refresh();这里面就是启动整个spring容器的代码。
    我们找到ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); -> refreshBeanFactory(); ->loadBeanDefinitions(beanFactory);
    loadBeanDefinitions就是实现加载我们xml里面的bean方法。

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // Create a new XmlBeanDefinitionReader for the given BeanFactory.
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // Configure the bean definition reader with this context's
            // resource loading environment.
            beanDefinitionReader.setEnvironment(getEnvironment());
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            // Allow a subclass to provide custom initialization of the reader,
            // then proceed with actually loading the bean definitions.
            initBeanDefinitionReader(beanDefinitionReader);
            loadBeanDefinitions(beanDefinitionReader);
        }
    

    我们可以看到大致流程就是先拿到解析xml的Reader,最后调用loadBeanDefinitions(beanDefinitionReader);,

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
            String[] configLocations = getConfigLocations();
            if (configLocations != null) {
                for (String configLocation : configLocations) {
                    reader.loadBeanDefinitions(configLocation);
                }
            }
        }
    

    这里面是把我们在web.xml里面配置的xml路径

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/spring-context.xml</param-value>
      </context-param>
    

    读取出来挨个解析,接着我们可以一直往下跟,AbstractBeanDefinitionReader.loadBeanDefinitions(Resource... resources)->XmlBeanDefinitionReader.loadBeanDefinitions();->doLoadBeanDefinitions();->doLoadDocument(inputSource, resource)解析xml节点->registerBeanDefinitions(doc, resource)注册bean->documentReader.registerBeanDefinitions(doc, createReaderContext(resource))我们注意这里有个createReaderContext(resource)这个方法会加载解析xml标签的类,比如<bean/> <context:component-scan/>等等 ,如下图

    image.png
    ->doRegisterBeanDefinitions(root)->parseBeanDefinitions(root, this.delegate)
    这里开始对xml里面的节点进行解析
    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);
            }
        }
    

    delegate.isDefaultNamespace(ele)这边我们先判断一下是不是http://www.springframework.org/schema/beans这个xsd里面的标签,其中包括beans,import,alias,bean。如果不在这几个里面,再去获取特殊的标签handler

    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;
            }
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }
    

    对应的handler就会解析相应的标签里面要生成的bean。
    举例ComponentScanBeanDefinitionParser (解析component-scan标签下的bean)

    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);//解析标签填的包下的class,
            registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    
            return null;
        }
    
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
            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);//获取beanname
                    if (candidate instanceof AbstractBeanDefinition) {
                        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                    }
                    if (candidate instanceof AnnotatedBeanDefinition) {
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                    }
                    if (checkCandidate(beanName, candidate)) {//检验bean是否已经存在
                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                        beanDefinitions.add(definitionHolder);
                        registerBeanDefinition(definitionHolder, this.registry);//注入bean 添加到beanDefinitionMap里面
                    }
                }
            }
            return beanDefinitions;
        }
    

    相关文章

      网友评论

          本文标题:Spring源码之loadbeandefinition

          本文链接:https://www.haomeiwen.com/subject/dsabzftx.html