SpringMVC 项目启动的加载顺序(一)父类容器的启动

最近在研究Spring MVC项目的启动加载顺序,做一个具体说明:

一、web容器的启动

1、web项目启动的时候,容器会优先读取web.xml文件,并且先找到<listener></listener>和<context-param></context-param>两个节点;

2、容器会创建一个ServlextContext上下文,并解析<context-param></context-param>节点,存入上下文中;

3、容器创建listener实例,并执行listener实例中的contextInitialized(ServletContextEvent sce)方法;

4、执行filter节点信息;

5、最后创建servlet;

二、Web容器启动Spring 容器

web容器启动的时候,SpringMVC配置的ContextLoadListener将会被启动,

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }

    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }

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

    public void contextDestroyed(ServletContextEvent event) {
        this.closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

ContextLoadListener会被触发初始化事件,执行initWebApplicationContext方法;

if(this.context == null) {
    this.context = this.createWebApplicationContext(servletContext);
}

if(this.context instanceof ConfigurableWebApplicationContext) {
    ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context;
    if(!err.isActive()) {
        if(err.getParent() == null) {
            ApplicationContext elapsedTime = this.loadParentContext(servletContext);
            err.setParent(elapsedTime);
        }

        this.configureAndRefreshWebApplicationContext(err, servletContext);
    }
}

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

创建好Context实例后,执行configureAndRefreshWebApplicationContext方法。非常重要的一点,这里会loadParentContext,并且加载ApplicationContext中的bean 资源文件。configureAndRefreshWebApplicationContext方法会执行Context的refresh方法

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    。。。
    this.customizeContext(sc, wac);
    wac.refresh();
}

Spring加载Bean:

public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();        // conetxt 的准备工作
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 获取bean工厂   
        this.prepareBeanFactory(beanFactory);    // 准备这个上线文需要使用的bean工厂

        try {
            this.postProcessBeanFactory(beanFactory);    // Allows post-processing of the bean factory in context subclasses.
            this.invokeBeanFactoryPostProcessors(beanFactory);    // Invoke factory processors registered as beans in the context
            this.registerBeanPostProcessors(beanFactory);    // Register bean processors that intercept bean creation.
            this.initMessageSource();
            this.initApplicationEventMulticaster();    // Initialize event multicaster for this context
            this.onRefresh();    // Initialize other special beans in specific context subclasses.
            this.registerListeners();    // Check for listener beans and register them.
            this.finishBeanFactoryInitialization(beanFactory);    // Instantiate all remaining (non-lazy-init) singletons.
            this.finishRefresh(); // Last step: publish corresponding event.
        } catch (BeansException var9) {
            if(this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();
            this.cancelRefresh(var9);
            throw var9;
        } finally {
            this.resetCommonCaches();
        }

    }
}

其中,finishBeanFactoryInitialization方法,

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    if(beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
        beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
    }

    if(!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
            public String resolveStringValue(String strVal) {
                return AbstractApplicationContext.this.getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }

    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    String[] var3 = weaverAwareNames;
    int var4 = weaverAwareNames.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        String weaverAwareName = var3[var5];
        this.getBean(weaverAwareName);
    }

    beanFactory.setTempClassLoader((ClassLoader)null);
    beanFactory.freezeConfiguration();
    beanFactory.preInstantiateSingletons();
}

到了beanFactory.preInstantiateSingletons();发现类还没有被初始化,继续有到DefaultListableBeanFactory有:

public void preInstantiateSingletons() throws BeansException {

    ArrayList beanNames = new ArrayList(this.beanDefinitionNames);
    Iterator var2 = beanNames.iterator();
    // Trigger initialization of all non-lazy singleton beans...
    while(true) {
        while(true) {
            String beanName;
            RootBeanDefinition singletonInstance;
            do {
                do {
                    do {
                        if(!var2.hasNext()) {
                            var2 = beanNames.iterator();

                            while(var2.hasNext()) {
                                beanName = (String)var2.next();
                                Object singletonInstance1 = this.getSingleton(beanName);
                                if(singletonInstance1 instanceof SmartInitializingSingleton) {
                                    final SmartInitializingSingleton smartSingleton1 = (SmartInitializingSingleton)singletonInstance1;
                                    if(System.getSecurityManager() != null) {
                                        AccessController.doPrivileged(new PrivilegedAction() {
                                            public Object run() {
                                                smartSingleton1.afterSingletonsInstantiated();
                                                return null;
                                            }
                                        }, this.getAccessControlContext());
                                    } else {
                                        smartSingleton1.afterSingletonsInstantiated();
                                    }
                                }
                            }

                            return;
                        }

                        beanName = (String)var2.next();
                        singletonInstance = this.getMergedLocalBeanDefinition(beanName);
                    } while(singletonInstance.isAbstract());
                } while(!singletonInstance.isSingleton());
            } while(singletonInstance.isLazyInit());

            if(this.isFactoryBean(beanName)) {
                final FactoryBean smartSingleton = (FactoryBean)this.getBean("&" + beanName);
                boolean isEagerInit;
                if(System.getSecurityManager() != null && smartSingleton instanceof SmartFactoryBean) {
                    isEagerInit = ((Boolean)AccessController.doPrivileged(new PrivilegedAction() {
                        public Boolean run() {
                            return Boolean.valueOf(((SmartFactoryBean)smartSingleton).isEagerInit());
                        }
                    }, this.getAccessControlContext())).booleanValue();
                } else {
                    isEagerInit = smartSingleton instanceof SmartFactoryBean && ((SmartFactoryBean)smartSingleton).isEagerInit();
                }

                if(isEagerInit) {
                    this.getBean(beanName);
                }
            } else {
                this.getBean(beanName);
            }
        }
    }
}

其中,

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if(singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        Map var4 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if(singletonObject == null && allowEarlyReference) {
                ObjectFactory singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                if(singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }

    return singletonObject != NULL_OBJECT?singletonObject:null;
}

会执行获取bean的实例,并且将bean的实例存下来。

最后,finishRefresh方法会发布Context刷新完成的事件:

protected void finishRefresh() {
    this.initLifecycleProcessor();
    this.getLifecycleProcessor().onRefresh();
    this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
    LiveBeansView.registerApplicationContext(this);
}

但是,在执行Bean的实例化之前,是在obtainFreshBeanFactory方法中加载Bean的定义文件的,

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

    return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
    if(this.hasBeanFactory()) {
        this.destroyBeans();
        this.closeBeanFactory();
    }

    try {
        DefaultListableBeanFactory ex = this.createBeanFactory();
        ex.setSerializationId(this.getId());
        this.customizeBeanFactory(ex);
        this.loadBeanDefinitions(ex);
        Object var2 = this.beanFactoryMonitor;
        synchronized(this.beanFactoryMonitor) {
            this.beanFactory = ex;
        }
    } catch (IOException var5) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
    }
}

如果有BeanFactory存在,先会销毁所有的bean,并且关闭beanFactory,然后在重新创建一个BeanFactory,加载BeanDefinition。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    this.initBeanDefinitionReader(beanDefinitionReader);
    this.loadBeanDefinitions(beanDefinitionReader);
}

LoadBeanDefinitions会从Xml资源读取器中获取信息:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    this.initBeanDefinitionReader(beanDefinitionReader);
    this.loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    String[] configLocations = this.getConfigLocations();
    if(configLocations != null) {
        String[] var3 = configLocations;
        int var4 = configLocations.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String configLocation = var3[var5];
            reader.loadBeanDefinitions(configLocation);
        }
    }

}
public void setConfigLocations(String... locations) {
    if(locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        this.configLocations = new String[locations.length];

        for(int i = 0; i < locations.length; ++i) {
            this.configLocations[i] = this.resolvePath(locations[i]).trim();
        }
    } else {
        this.configLocations = null;
    }

}

综上,Bean的定义来源于资源文件,从资源文件上获取定义的加载顺序,从BeanDefinition的加载顺序,确定被实例化的顺序。

obtainFreshBeanFactory()

->refreshBeanFactory()

->loadBeanDefinitions(beanFactory)属于XmlWebApplicationContext

->reader.loadBeanDefinitions(configLocation)

->loadBeanDefinitions(location, null) 

->int loadCount = loadBeanDefinitions(resources)

->counter += loadBeanDefinitions(resource)

->loadBeanDefinitions(new EncodedResource(resource))

->doLoadBeanDefinitions(inputSource, encodedResource.getResource())

->registerBeanDefinitions(doc, resource)

->documentReader.registerBeanDefinitions(doc, createReaderContext(resource))

->doRegisterBeanDefinitions(root)

->parseBeanDefinitions(root, this.delegate)

->delegate.parseCustomElement(root)

->parseCustomElement(ele, null)

->handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))

->findParserForElement(element, parserContext).parse(element, parserContext)

->parse(element, parserContext)属于ComponentScanBeanDefinitionParser

关键步骤是parse方法,Spring中自带的Parse有:

SpringMVC 项目启动的加载顺序(一)父类容器的启动

常用的componentScan方法:

public BeanDefinition parse(Element element, ParserContext parserContext) {
    String basePackage = element.getAttribute("base-package");
    basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
    String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ",; \t\n");
    ClassPathBeanDefinitionScanner scanner = this.configureScanner(parserContext, element);
    Set beanDefinitions = scanner.doScan(basePackages);
    this.registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    return null;
}

doScan方法返回的是一个Set集合,

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    LinkedHashSet beanDefinitions = new LinkedHashSet();
    String[] var3 = basePackages;
    int var4 = basePackages.length;

    for(int var5 = 0; var5 < var4; ++var5) {
        String basePackage = var3[var5];
        Set candidates = this.findCandidateComponents(basePackage);
        Iterator var8 = candidates.iterator();

        while(var8.hasNext()) {
            BeanDefinition candidate = (BeanDefinition)var8.next();
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if(candidate instanceof AbstractBeanDefinition) {
                this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
            }

            if(candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
            }

            if(this.checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                this.registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }

    return beanDefinitions;
}

在查找候选的定义方法中有:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    LinkedHashSet candidates = new LinkedHashSet();

    try {
        String ex = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        Resource[] resources = this.resourcePatternResolver.getResources(ex);
        boolean traceEnabled = this.logger.isTraceEnabled();
        boolean debugEnabled = this.logger.isDebugEnabled();
        Resource[] var7 = resources;
        int var8 = resources.length;

        for(int var9 = 0; var9 < var8; ++var9) {
            Resource resource = var7[var9];
            if(traceEnabled) {
                this.logger.trace("Scanning " + resource);
            }

            if(resource.isReadable()) {
                try {
                    MetadataReader ex1 = this.metadataReaderFactory.getMetadataReader(resource);
                    if(this.isCandidateComponent(ex1)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(ex1);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        if(this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
                            if(debugEnabled) {
                                this.logger.debug("Identified candidate component class: " + resource);
                            }

                            candidates.add(sbd);
                        } else if(debugEnabled) {
                            this.logger.debug("Ignored because not a concrete top-level class: " + resource);
                        }
                    } else if(traceEnabled) {
                        this.logger.trace("Ignored because not matching any filter: " + resource);
                    }
                } catch (Throwable var13) {
                    throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var13);
                }
            } else if(traceEnabled) {
                this.logger.trace("Ignored because not readable: " + resource);
            }
        }

        return candidates;
    } catch (IOException var14) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var14);
    }
}

直接将ScannedGenericBeanDefinition加入里Set集合,这个类的继承关系有:

SpringMVC 项目启动的加载顺序(一)父类容器的启动