Java Spring的refresh方法你知道嗎
spring的refresh方法
前置知識
方法入口
// org.springframework.context.support.AbstractApplicationContext#refresh
類的結(jié)構(gòu)圖
BeanDefinition 接口定義
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { // 我們可以看到,默認(rèn)只提供 sington 和 prototype 兩種, // 很多讀者可能知道還有 request, session, globalSession, application, websocket 這幾種, // 不過,它們屬于基于 web 的擴(kuò)展。 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 比較不重要,直接跳過吧 int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // 設(shè)置父 Bean,這里涉及到 bean 繼承,不是 java 繼承。請參見附錄的詳細(xì)介紹 // 一句話就是:繼承父 Bean 的配置信息而已 void setParentName(String parentName); // 獲取父 Bean String getParentName(); // 設(shè)置 Bean 的類名稱,將來是要通過反射來生成實(shí)例的 void setBeanClassName(String beanClassName); // 獲取 Bean 的類名稱 String getBeanClassName(); // 設(shè)置 bean 的 scope void setScope(String scope); String getScope(); // 設(shè)置是否懶加載 void setLazyInit(boolean lazyInit); boolean isLazyInit(); // 設(shè)置該 Bean 依賴的所有的 Bean,注意,這里的依賴不是指屬性依賴(如 @Autowire 標(biāo)記的), // 是 depends-on="" 屬性設(shè)置的值。 void setDependsOn(String... dependsOn); // 返回該 Bean 的所有依賴 String[] getDependsOn(); // 設(shè)置該 Bean 是否可以注入到其他 Bean 中,只對根據(jù)類型注入有效, // 如果根據(jù)名稱注入,即使這邊設(shè)置了 false,也是可以的 void setAutowireCandidate(boolean autowireCandidate); // 該 Bean 是否可以注入到其他 Bean 中 boolean isAutowireCandidate(); // 主要的。同一接口的多個(gè)實(shí)現(xiàn),如果不指定名字的話,Spring 會優(yōu)先選擇設(shè)置 primary 為 true 的 bean void setPrimary(boolean primary); // 是否是 primary 的 boolean isPrimary(); // 如果該 Bean 采用工廠方法生成,指定工廠名稱。對工廠不熟悉的讀者,請參加附錄 // 一句話就是:有些實(shí)例不是用反射生成的,而是用工廠模式生成的 void setFactoryBeanName(String factoryBeanName); // 獲取工廠名稱 String getFactoryBeanName(); // 指定工廠類中的 工廠方法名稱 void setFactoryMethodName(String factoryMethodName); // 獲取工廠類中的 工廠方法名稱 String getFactoryMethodName(); // 構(gòu)造器參數(shù) ConstructorArgumentValues getConstructorArgumentValues(); // Bean 中的屬性值,后面給 bean 注入屬性值的時(shí)候會說到 MutablePropertyValues getPropertyValues(); // 是否 singleton boolean isSingleton(); // 是否 prototype boolean isPrototype(); // 如果這個(gè) Bean 是被設(shè)置為 abstract,那么不能實(shí)例化, // 常用于作為 父bean 用于繼承,其實(shí)也很少用...... boolean isAbstract(); int getRole(); String getDescription(); String getResourceDescription(); BeanDefinition getOriginatingBeanDefinition(); }
refresh 這里簡單說下為什么是 refresh(),而不是 init() 這種名字的方法。因?yàn)?ApplicationContext 建立起來以后,其實(shí)我們是可以通過調(diào)用 refresh() 這個(gè)方法重建的,refresh() 會將原來的 ApplicationContext 銷毀,然后再重新執(zhí)行一次初始化操作。
@Override public void refresh() throws BeansException, IllegalStateException { // 來個(gè)鎖,不然 refresh() 還沒結(jié)束,你又來個(gè)啟動(dòng)或銷毀容器的操作,那不就亂套了嘛 synchronized (this.startupShutdownMonitor) { // 準(zhǔn)備工作,記錄下容器的啟動(dòng)時(shí)間、標(biāo)記“已啟動(dòng)”狀態(tài)、處理配置文件中的占位符 prepareRefresh(); // 這步比較關(guān)鍵,這步完成后,配置文件就會解析成一個(gè)個(gè) Bean 定義,注冊到 BeanFactory 中, // 當(dāng)然,這里說的 Bean 還沒有初始化,只是配置信息都提取出來了, // 注冊也只是將這些信息都保存到了注冊中心(說到底核心是一個(gè) beanName-> beanDefinition 的 map) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 設(shè)置 BeanFactory 的類加載器,添加幾個(gè) BeanPostProcessor,手動(dòng)注冊幾個(gè)特殊的 bean // 這塊待會會展開說 prepareBeanFactory(beanFactory); try { // 【這里需要知道 BeanFactoryPostProcessor 這個(gè)知識點(diǎn),Bean 如果實(shí)現(xiàn)了此接口, // 那么在容器初始化以后,Spring 會負(fù)責(zé)調(diào)用里面的 postProcessBeanFactory 方法?!? // 這里是提供給子類的擴(kuò)展點(diǎn),到這里的時(shí)候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化 // 具體的子類可以在這步的時(shí)候添加一些特殊的 BeanFactoryPostProcessor 的實(shí)現(xiàn)類或做點(diǎn)什么事 postProcessBeanFactory(beanFactory); // 調(diào)用 BeanFactoryPostProcessor 各個(gè)實(shí)現(xiàn)類的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 注冊 BeanPostProcessor 的實(shí)現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別 // 此接口兩個(gè)方法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 兩個(gè)方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行。注意,到這里 Bean 還沒初始化 registerBeanPostProcessors(beanFactory); // 初始化當(dāng)前 ApplicationContext 的 MessageSource,國際化這里就不展開說了,不然沒完沒了了 initMessageSource(); // 初始化當(dāng)前 ApplicationContext 的事件廣播器,這里也不展開了 initApplicationEventMulticaster(); // 從方法名就可以知道,典型的模板方法(鉤子方法), // 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前) onRefresh(); // 注冊事件監(jiān)聽器,監(jiān)聽器需要實(shí)現(xiàn) ApplicationListener 接口。這也不是我們的重點(diǎn),過 registerListeners(); // 重點(diǎn),重點(diǎn),重點(diǎn) // 初始化所有的 singleton beans //(lazy-init 的除外) finishBeanFactoryInitialization(beanFactory); // 最后,廣播事件,ApplicationContext 初始化完成 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. // 銷毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源 destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // 把異常往外拋 throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
創(chuàng)建 Bean 容器前的準(zhǔn)備工作
// 準(zhǔn)備工作 protected void prepareRefresh() { // 記錄啟動(dòng)時(shí)間, // 將 active 屬性設(shè)置為 true,closed 屬性設(shè)置為 false,它們都是 AtomicBoolean 類型 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 初始化上下文環(huán)境中的任何占位符屬性源。 initPropertySources(); // 校驗(yàn) xml 配置文件 getEnvironment().validateRequiredProperties(); // 初始化事件集合 this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
創(chuàng)建 Bean 容器,加載并注冊 Bean
// 最重要的方法之一,這里將會初始化 BeanFactory、加載 Bean、注冊 Bean 等等。 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 關(guān)閉舊的 BeanFactory (如果有),創(chuàng)建新的 BeanFactory,加載 Bean 定義、注冊 Bean 等等 refreshBeanFactory(); // 返回剛剛創(chuàng)建的 BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } // refreshBeanFactory @Override protected final void refreshBeanFactory() throws BeansException { // 如果 ApplicationContext 中已經(jīng)加載過 BeanFactory 了,銷毀所有 Bean,關(guān)閉 BeanFactory // 注意,應(yīng)用中 BeanFactory 本來就是可以多個(gè)的,這里可不是說應(yīng)用全局是否有 BeanFactory,而是當(dāng)前 // ApplicationContext 是否有 BeanFactory if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 初始化一個(gè) DefaultListableBeanFactory,為什么用這個(gè),我們馬上說。 DefaultListableBeanFactory beanFactory = createBeanFactory(); // 用于 BeanFactory 的序列化,我想大部分人應(yīng)該都用不到 beanFactory.setSerializationId(getId()); // 下面這兩個(gè)方法很重要,別跟丟了,具體細(xì)節(jié)之后說 // 設(shè)置 BeanFactory 的兩個(gè)配置屬性:是否允許 Bean 覆蓋、是否允許循環(huán)引用 customizeBeanFactory(beanFactory); // 加載 Bean 到 BeanFactory 中 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } // customizeBeanFactory 配置是否允許 BeanDefinition 覆蓋、是否允許循環(huán)引用。 protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { // 是否允許 Bean 定義覆蓋 在配置文件中定義 bean 時(shí)使用了相同的 id 或 name,默認(rèn)情況下,allowBeanDefinitionOverriding 屬性為 null,如果在同一配置文件中重復(fù)了,會拋錯(cuò),但是如果不是同一配置文件中,會發(fā)生覆蓋。 beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.allowCircularReferences != null) { // 是否允許 Bean 間的循環(huán)依賴 如:A 依賴 B,而 B 依賴 A?;?A 依賴 B,B 依賴 C,而 C 依賴 A。 beanFactory.setAllowCircularReferences(this.allowCircularReferences); } } // loadBeanDefinitions 加載bean,放入 BeanFactory 中 org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory) /** 我們可以看到,此方法將通過一個(gè) XmlBeanDefinitionReader 實(shí)例來加載各個(gè) Bean。*/ @Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // 給這個(gè) BeanFactory 實(shí)例化一個(gè) XmlBeanDefinitionReader 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)); // 初始化 BeanDefinitionReader,其實(shí)這個(gè)是提供給子類覆寫的, // 我看了一下,沒有類覆寫這個(gè)方法,我們姑且當(dāng)做不重要吧 initBeanDefinitionReader(beanDefinitionReader); // 重點(diǎn)來了,繼續(xù)往下 loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { // 往下看 reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { // 2 reader.loadBeanDefinitions(configLocations); } } // 上面雖然有兩個(gè)分支,不過第二個(gè)分支很快通過解析路徑轉(zhuǎn)換為 Resource 以后也會進(jìn)到這里 @Override public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; // 注意這里是個(gè) for 循環(huán),也就是每個(gè)文件是一個(gè) resource for (Resource resource : resources) { // 繼續(xù)往下看 counter += loadBeanDefinitions(resource); } // 最后返回 counter,表示總共加載了多少的 BeanDefinition return counter; } // XmlBeanDefinitionReader 303 @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } // XmlBeanDefinitionReader 314 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.getResource()); } // 用一個(gè) ThreadLocal 來存放配置文件資源 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(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(); } } } // 還在這個(gè)文件中,第 388 行 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 這里就不看了,將 xml 文件轉(zhuǎn)換為 Document 對象 Document doc = doLoadDocument(inputSource, resource); // 繼續(xù) return registerBeanDefinitions(doc, resource); } catch (... } // 還在這個(gè)文件中,第 505 行 // 返回值:返回從當(dāng)前配置文件加載了多少數(shù)量的 Bean public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 這里 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } // DefaultBeanDefinitionDocumentReader 90 @Override public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); // 從 xml 根節(jié)點(diǎn)開始解析文件 doRegisterBeanDefinitions(root); } // doRegisterBeanDefinitions 經(jīng)過漫長的鏈路,一個(gè)配置文件終于轉(zhuǎn)換為一顆 DOM 樹了,注意,這里指的是其中一個(gè)配置文件,不是所有的,讀者可以看到上面有個(gè) for 循環(huán)的。下面開始從根節(jié)點(diǎn)開始解析: // DefaultBeanDefinitionDocumentReader 116 protected void doRegisterBeanDefinitions(Element root) { // 我們看名字就知道,BeanDefinitionParserDelegate 必定是一個(gè)重要的類,它負(fù)責(zé)解析 Bean 定義, // 這里為什么要定義一個(gè) parent? 看到后面就知道了,是遞歸問題, // 因?yàn)?<beans /> 內(nèi)部是可以定義 <beans /> 的,所以這個(gè)方法的 root 其實(shí)不一定就是 xml 的根節(jié)點(diǎn),也可以是嵌套在里面的 <beans /> 節(jié)點(diǎn),從源碼分析的角度,我們當(dāng)做根節(jié)點(diǎn)就好了 BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { // 這塊說的是根節(jié)點(diǎn) <beans ... profile="dev" /> 中的 profile 是否是當(dāng)前環(huán)境需要的, // 如果當(dāng)前環(huán)境配置的 profile 不包含此 profile,那就直接 return 了,不對此 <beans /> 解析 // 不熟悉 profile 為何物,不熟悉怎么配置 profile 讀者的請移步附錄區(qū) 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; } } } preProcessXml(root); // 鉤子 preProcessXml(root) 和 postProcessXml(root) 是給子類用的鉤子方法,鑒于沒有被使用到,也不是我們的重點(diǎn),我們直接跳過。 // 往下看 parseBeanDefinitions(root, this.delegate); postProcessXml(root); // 鉤子 this.delegate = parent; } // default namespace 涉及到的就四個(gè)標(biāo)簽 <import />、<alias />、<bean /> 和 <beans />, // 其他的屬于 custom 的 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)) { // 解析 default namespace 下面的幾個(gè)元素 parseDefaultElement(ele, delegate); } else { // 解析其他 namespace 的元素 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 處理 <import /> 標(biāo)簽 importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 處理 <alias /> 標(biāo)簽定義 // <alias name="fromName" alias="toName"/> processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 處理 <bean /> 標(biāo)簽定義,這也算是我們的重點(diǎn)吧 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 如果碰到的是嵌套的 <beans /> 標(biāo)簽,需要遞歸 doRegisterBeanDefinitions(ele); } } // DefaultBeanDefinitionDocumentReader 298 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { // 將 <bean /> 節(jié)點(diǎn)中的信息提取出來,然后封裝到一個(gè) BeanDefinitionHolder 中,細(xì)節(jié)往下看 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // 下面的幾行先不要看,跳過先,跳過先,跳過先,后面會繼續(xù)說的 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)); } } // BeanDefinitionParserDelegate 428 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); // 將 name 屬性的定義按照 “逗號、分號、空格” 切分,形成一個(gè) 別名列表數(shù)組, // 當(dāng)然,如果你不定義 name 屬性的話,就是空的了 // 我在附錄中簡單介紹了一下 id 和 name 的配置,大家可以看一眼,有個(gè)20秒就可以了 if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; // 如果沒有指定id, 那么用別名列表的第一個(gè)名字作為beanName if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } // 根據(jù) <bean ...>...</bean> 中的配置創(chuàng)建 BeanDefinition,然后把配置中的信息都設(shè)置到實(shí)例中, // 細(xì)節(jié)后面細(xì)說,先知道下面這行結(jié)束后,一個(gè) BeanDefinition 實(shí)例就出來了。 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); // 到這里,整個(gè) <bean /> 標(biāo)簽就算解析結(jié)束了,一個(gè) BeanDefinition 就形成了。 if (beanDefinition != null) { // 如果都沒有設(shè)置 id 和 name,那么此時(shí)的 beanName 就會為 null,進(jìn)入下面這塊代碼產(chǎn)生 // 如果讀者不感興趣的話,我覺得不需要關(guān)心這塊代碼,對本文源碼分析來說,這些東西不重要 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) {// 按照我們的思路,這里 containingBean 是 null 的 beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // 如果我們不定義 id 和 name,那么我們引言里的那個(gè)例子: // 1. beanName 為:com.javadoop.example.MessageServiceImpl#0 // 2. beanClassName 為:com.javadoop.example.MessageServiceImpl beanName = this.readerContext.generateBeanName(beanDefinition); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { // 把 beanClassName 設(shè)置為 Bean 的別名 aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); // 返回 BeanDefinitionHolder return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
看到這里的時(shí)候,我覺得讀者就應(yīng)該站在高處看 ApplicationContext 了,ApplicationContext 繼承自 BeanFactory,但是它不應(yīng)該被理解為 BeanFactory 的實(shí)現(xiàn)類,而是說其內(nèi)部持有一個(gè)實(shí)例化的 BeanFactory(DefaultListableBeanFactory)。以后所有的 BeanFactory 相關(guān)的操作其實(shí)是委托給這個(gè)實(shí)例來處理的。
我們說說為什么選擇實(shí)例化 DefaultListableBeanFactory ?前面我們說了有個(gè)很重要的接口 ConfigurableListableBeanFactory,它實(shí)現(xiàn)了 BeanFactory 下面一層的所有三個(gè)接口,我把之前的繼承圖再拿過來大家再仔細(xì)看一下:
我們可以看到 ConfigurableListableBeanFactory
只有一個(gè)實(shí)現(xiàn)類DefaultListableBeanFactory
,而且實(shí)現(xiàn)類 DefaultListableBeanFactory
還通過實(shí)現(xiàn)右邊的 AbstractAutowireCapableBeanFactory
通吃了右路。所以結(jié)論就是,最底下這個(gè)家伙 DefaultListableBeanFactory
基本上是最牛的 BeanFactory 了,這也是為什么這邊會使用這個(gè)類來實(shí)例化的原因。
循環(huán)依賴
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Springboot?2.x?RabbitTemplate默認(rèn)消息持久化的原因解析
這篇文章主要介紹了Springboot?2.x?RabbitTemplate默認(rèn)消息持久化的原因解析,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-0310個(gè)實(shí)現(xiàn)Java集合,Map類型自由轉(zhuǎn)換的實(shí)用工具方法
這篇文章主要為大家整理了整理了10個(gè)實(shí)用工具方法,可以滿足?Collection、List、Set、Map?之間各種類型轉(zhuǎn)化,文中的示例代碼講解詳細(xì),需要的可以參考下2023-09-09Spring boot打包jar分離lib和resources方法實(shí)例
這篇文章主要介紹了Spring boot打包jar分離lib和resources方法實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05面試題:Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字
這篇文章主要介紹了Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07基于eclipse.ini內(nèi)存設(shè)置的問題詳解
本篇文章是對eclipse.ini內(nèi)存設(shè)置的問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Spring boot 跳轉(zhuǎn)到j(luò)sp頁面的實(shí)現(xiàn)方法
本篇文章主要介紹了Spring boot 跳轉(zhuǎn)到j(luò)sp頁面的實(shí)現(xiàn)方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04