1. 程式人生 > >SpringMVC 專案啟動的載入順序(一)父類容器的啟動

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有:


常用的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集合,這個類的繼承關係有: