前言
在文章 ApplicationContext 體系結(jié)構(gòu) 中我們從一張 ApplicationContext 體系的類圖開始,介紹了 ApplicationContext 體系中各個類的繼承關(guān)系撬腾,接著分析了 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 類的構(gòu)造函數(shù)中前兩個函數(shù)的源碼螟蝙。從本篇文章開始,將重點介紹 refresh 函數(shù)民傻。
-
AbstractApplicationContext::refresh
ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 類均繼承了 AbstractApplicationContext 類胰默,refresh 方法在該類中實現(xiàn)。public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 刷新預(yù)處理 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // (1) 創(chuàng)建 IOC 容器(DefaultListableBeanFactory) // (2) 加載 xml 文件(最終生成 Document 對象) // (3) 讀取 Document 對象漓踢,完成 BeanDefinition 的加載和注冊 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 對IOC容器進(jìn)行預(yù)處理 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 調(diào)用BeanFactoryPostProcessor后置處理器對 BeanDefinition 處理 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注冊BeanPostProcessor后置處理器 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // STEP 7: 初始化一些消息源(比如處理國際化的i18n等消息源) initMessageSource(); // Initialize event multicaster for this context. // STEP 8: 初始化應(yīng)用事件廣播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // STEP 9: 初始化一些特殊的bean onRefresh(); // Check for listener beans and register them. // STEP 10: 注冊一些監(jiān)聽器 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // STEP 11: 實例化剩余的單例bean(非懶加載方式) // 注意事項:Bean的IoC牵署、DI和AOP都是發(fā)生在此步驟 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // STEP 12: 完成刷新時,需要發(fā)布對應(yīng)的事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
-
AbstractApplicationContext::prepareRefresh
protected void prepareRefresh() { // Switch to active. // 記錄啟動時間喧半,容器狀態(tài) this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment. // 空函數(shù)什么也沒做奴迅,初始化屬性配置在其子類中有實現(xiàn)(例如:AbstractRefreshableWebApplicationContext、GenericWebApplicationContext等) initPropertySources(); // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties /** * 1. 獲取 ConfigurableEnvironment * 2. 確保配置所有必須的屬性 **/ getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... // 創(chuàng)建早期時間監(jiān)聽器容集合挺据,保存早期監(jiān)聽器取具,也就是在之前已經(jīng)初始化的監(jiān)聽器脖隶。 if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... // 創(chuàng)建早期事件集合 this.earlyApplicationEvents = new LinkedHashSet<>(); }
-
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
創(chuàng)建 BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 1. refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
-
refreshBeanFactory
AbstractApplicationContext 中該方法為空,在子類 AbstractRefreshableApplicationContext(ClassPathXmlApplicationContext繼承該類)者填、GenericApplicationContext(AnnotationConfigApplicationContext繼承該類)中對該方法進(jìn)行了擴展浩村。-
AbstractRefreshableApplicationContext::refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException { // 若已存在 BeanFactory,則銷毀容器中的 Bean 實例占哟,將 BeanFactory 置為 null if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 創(chuàng)建 BeanFactory 實例心墅,類型為:DefaultListableBeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); // 定制beanFactory,設(shè)置相關(guān)屬性榨乎,包括是否允許覆蓋同名稱的不同定義的對象以及循環(huán)依賴 // 可在子類中去擴展定義屬性:allowBeanDefinitionOverriding, allowCircularReferences customizeBeanFactory(beanFactory); // 加載 BeanDefinition怎燥,并注冊到IoC容器中(重點) loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
- loadBeanDefinitions
在 AbstractRefreshableApplicationContext::refreshBeanFactory 中 loadBeanDefinitions 為重點代碼,接下來將詳細(xì)介紹改部分的代碼蜜暑。|-- AbstractRefreshableApplicationContext::refreshBeanFactory |-- AbstractXmlApplicationContext::loadBeanDefinitions:走了多個重載方法 |--AbstractBeanDefinitionReader::loadBeanDefinitions:走了多個重載方法 |--XmlBeanDefinitionReader::loadBeanDefinitions:走了多個重載方法 |--XmlBeanDefinitionReader::doLoadBeanDefinitions |--XmlBeanDefinitionReader::registerBeanDefinitions |-- DefaultBeanDefinitionDocumentReader ::registerBeanDefinitions ::doRegisterBeanDefinitions ::parseBeanDefinitions ::parseDefaultElement ::processBeanDefinition |--BeanDefinitionParserDelegate ::parseBeanDefinitionElement ::parseBeanDefinitionElement 1. AbstractRefreshableApplicationContext:主要用來對BeanFactory提供 refresh 功能铐姚。包括BeanFactory的創(chuàng)建和 BeanDefinition 的定義、解析肛捍、注冊操作隐绵。 2. AbstractXmlApplicationContext:提供對 xml 資源的解析功能,包括從Resource資源對象和資源路徑中加載XML文件拙毫。 3. AbstractBeanDefinitionReader:主要提供對于 BeanDefinition 對象的讀取功能依许。具體讀取工作交給子類實現(xiàn)。 4. XmlBeanDefinitionReader:主要通過 DOM4J 對于 XML資源 的讀取缀蹄、解析功能峭跳,并提供對于 BeanDefinition 的注冊功能。 5. DefaultBeanDefinitionDocumentReader 6. BeanDefinitionParserDelegate
- AbstractXmlApplicationContext::loadBeanDefinitions
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. // 創(chuàng)建 XmlBeanDefinitionReader缺前, 此時會初始化 ResourceLoaderLoader XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.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); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { // debug 中 configResourses 為 null Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { // 根據(jù)配置文件位置加載BeanDefinition reader.loadBeanDefinitions(configLocations); } } // AbstractBeanDefinitionReader::loadBeanDefinitions public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; for (String location : locations) { counter += loadBeanDefinitions(location); } return counter; } public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { // 初始化 XmlBeanDefinitionReader 時已經(jīng)初始化了 ResourceLoader // XmlBeanDefinitionReader 無法直接加載配置文件蛀醉,因此需要委托 ResourceLoader 將配置文件加載為 Resource 對象 ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); // 根據(jù) Resource 加載 BeanDefinition int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
- XmlBeanDefinitionReader::loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } // 核心代碼 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 將配置文件轉(zhuǎn)換為 Document 對象 Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } // .. 此處異常捕獲處理代碼省去 } public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 創(chuàng)建 DefaultBeanDefinitionDocumentReader 對象 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 1. 創(chuàng)建 Reader 上下文 // 2. 根據(jù) Document 對象加載 BeanDefinition documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
- XmlBeanDefinitionReader::registerBeanDefinitions
// 創(chuàng)建 XmlReaderContext, 需要創(chuàng)建 NameSpaceHandlerResolver 用來處理 xml 配置文件中的各命名空間 // 讀取 "META-INF/spring.handlers" 創(chuàng)建 DefaultNamespaceHandlerResolver public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); } public NamespaceHandlerResolver getNamespaceHandlerResolver() { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this.namespaceHandlerResolver; } protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader()); return new DefaultNamespaceHandlerResolver(cl); } public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) { //public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION); }
- DefaultBeanDefinitionDocumentReader::registerBeanDefinitions
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); } protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; // 根據(jù) Reader 上下文創(chuàng)建 BeanDefinitionParserDelegate this.delegate = createDelegate(getReaderContext(), root, parent); /** * BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); * delegate.initDefaults(root, parentDelegate); **/ 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)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } // 空函數(shù) preProcessXml(root); // 解析標(biāo)簽 parseBeanDefinitions(root, this.delegate); // 空函數(shù) 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)) { // 處理默認(rèn)的標(biāo)簽元素:bean/import/alias/beans parseDefaultElement(ele, delegate); } else { // 處理自定義的標(biāo)簽 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } 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)) { // 處理 bean 標(biāo)簽 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse 遞歸調(diào)用 doRegisterBeanDefinitions(ele); } } protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 解析 Bean 標(biāo)簽,創(chuàng)建 BeanDefinitionHolder 對象 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } } public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); // 注冊 BeanDefinition 至于 DefaultListableBeanFactory 的 beanDefinitionMap 中 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } // 自定義命名空間的解析衅码,如: context拯刁,aop,tx public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 根據(jù) META-INF/spring.handlers 中的配置逝段,找到 Namespace 對應(yīng)的 Handler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 調(diào)用 NamespaceHandler 實現(xiàn)的 parse 方法將 dom element 解析為 BeanDefinition return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
上述源碼流程即為 obtainFreshBeanFactory 的過程筛璧,主要完成了
- 創(chuàng)建了 DefaultListableBeanFactory;
- 讀取配置文件惹恃,完成了BeanDefinition的加載
引申:
在對自定義命名空間進(jìn)行處理時夭谤,會有一些預(yù)置的 BeanDefinition 的加載,例如對 context:annotation-config 標(biāo)簽處理時巫糙,會加載 ConfigurationClassPostProcessor 類(BeanFactoryPostProcessor)的 BeanDefinition, 在后續(xù) invokeBeanFactoryPostProcessors 方法中朗儒,會使用到該擴展點public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); // 對 @autowired、@ Resource 、@ PostConstruct醉锄、@ PreDestroy乏悄、@Required、@PersistenceContext 注解解析 registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); // 除了annotation-config對應(yīng)的注解解析外恳不,擴展了 @Component 注解的支持檩小,因此如果配制了 context:component-scan 就無須再配置 context:annotation-config registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
- loadBeanDefinitions
-
GenericApplicationContext::refreshBeanFactory
GenericApplicationContext 的 refresh 方法相比于 AbstractRefreshableApplicationContext 要簡單許多,只有一個 refresh 標(biāo)記的判斷以及序列化 ID 的設(shè)置protected final void refreshBeanFactory() throws IllegalStateException { if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } this.beanFactory.setSerializationId(getId()); }
-
-
總結(jié)
本篇文章中首先對 refresh 函數(shù)源碼進(jìn)行了簡單的分析烟勋,了解了各個函數(shù)大概的作用规求,然后針對 prepareRefresh 和 obtainFreshBeanFactory 函數(shù)做了詳細(xì)的分析。
- prepareRefresh
在該函數(shù)中進(jìn)行了一些容器刷新的準(zhǔn)備卵惦,如記錄容器啟動時間阻肿、定義早期事件的監(jiān)聽器等 - obtainFreshBeanFactory
AbstractApplicationContext 中該方法為空,在其子類 AbstractRefreshableApplicationContext 和 GenericApplicationContext 中對該方法進(jìn)行了擴展沮尿。- AbstractRefreshableApplicationContext
方法中首先定義了 beanDefinitionReader丛塌,然后讀取配置文件將配置文件中定義的 Bean 信息加載為 BeanDefinition,需要注意的是其中包含一些自定義命名空間的解析畜疾。 - GenericApplicationContext
僅做了refresh 標(biāo)記的判斷以及序列化 ID 的設(shè)置
- AbstractRefreshableApplicationContext