Spring原始碼學習之IOC實現原理(二)-ApplicationContext
一.Spring核心元件結構
總的來說Spring共有三個核心元件,分別為Core,Context,Bean.三大核心元件的協同工作主要表現在 :Bean是包裝我們應用程式自定義物件Object的,Object中存有資料,而Context就是為了這些資料存放提供一個生存環境,儲存各個 bean之間的對應關係,並且維護好這些對應關係。Context就是一個Bean關係的集合,也就是我們所謂的IOC容器。Core就是Context 在發現、建立、維護Bean之間關係所需要的一些工具,如資源的載入,資源的抽象等。 (《深入分析Java Web技術內幕》)
1.Bean元件
前面介紹的BeanFactory體系就屬於Bean元件,位於org.springframework.beans子包factory包下面。這個包主要解決三個問題,Bean的定義,Bean的建立,Bean的解析。
1. org.springframework.beans, 包含了操作java bean的介面和類。This package contains interfaces and classes for manipulating Java beans. It is used by most other Spring packages. ***
2. org.springframework.beans.annotation, 支援包,提供對java 5註解處理bean樣式的支援。 3. org.springframework.beans.factory, 實現spring輕量級IoC容器的核心包。*** 4. org.springframework.beans.factory.access, 定位和獲取bean工程的輔助工具類。 5. org.springframework.beans.factory.access.el,從統一樣式的EL 獲取spring beanFactory的支援類 6. org.springframework.beans.factory.annotation, 配置基於註解驅動的bean的支援包。*** 7. org.springframework.beans.factory.config, bean工廠的SPI介面和配置相關的處理類。 8. org.springframework.beans.factory.parsing, bean definition解析的支援基礎類 9. org.springframework.beans.factory.serviceloader, jdk1.6 ServiceLoader基礎類的支援包。 10. org.springframework.beans.factory.support,org.springframework.beans.factory包的支援類 11. org.springframework.beans.factory.wiring, 一種決定一個bean例項的元資料的機制。 12. org.springframework.beans.factory.xml, 包含了一個基於xml的beanFactory實現,也包含一個標準的spring-beans的dtd 13. org.springframework.beans.propertyeditors, 屬性編輯器,用來將string型別的值轉換為object型別,例如:java.util.Properties 14. org.springframework.beans.support,org.springframework.beans的支援包,像:一組bean的排序和保持工具類等
Bean的定義由BeanDefinition抽象出來,也是IOC容器的內部資料結構。BeanDefinition完整的描述了xml檔案中關於<bean>節點的所有資訊。當Spring解析一個<bean>節點後,在IOC容器內部就會轉換為BeanDefinition物件。而最終例項化時,所使用的物件就是RootBeanDefinition物件。
Bean的建立,採用的是典型的工廠模式,採用的體系即(一)中所說的BeanFactory體系結構。主要的類是DefaultListableBeanFactory,其完整的實現了IOC容器的功能。
Bean的解析,主要就是對於Spring的配置檔案進行解析處理,從中解析出相應的資訊以用來生成Bean的物件。 其中主要用於解析的實現類就是DefaultBeanDefinitionDocumentReader。
2.Core元件
Core元件作為Spring的核心元件,其中包含了很多關鍵類,一個重要的組成部分就是定義了資源的訪問方式。如之前用到的ClassPathResource就是其中的一個典型的資源抽象形式。資源的頂級介面為Resource,它繼承自InputStreamSource,實現了其getInputStream方法,返回的是InputStream類。這樣所有的資源就是通過該方法來獲取輸入流的。對於資源的載入,也實現了統一,遮蔽了資源提供者。定義了一個資源載入頂級介面 ResourceLoader ,它預設的載入就是DefaultResourceLoader。
2.1InputStreamSource
該介面只有一個抽象方法
public interface InputStreamSource { /** * Return an {@link InputStream}. */ InputStream getInputStream() throws IOException; }
2.2 Resource
作為頂級介面,也是再各個類中呼叫資源時應用最為廣泛的介面,充分體現了面向介面程式設計的思想。
/** * Interface for a resource descriptor that abstracts from the actual * type of underlying resource, such as a file or class path resource. */ public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }
這就是該介面定義的方法,都是顯而易見的方法,同時也是對於資源類來說應用最多的方法。
2.3ClassPathResource
/** * This implementation opens an InputStream for the given class path resource. * @see java.lang.ClassLoader#getResourceAsStream(String) * @see java.lang.Class#getResourceAsStream(String) */ @Override public InputStream getInputStream() throws IOException { InputStream is; if (this.clazz != null) { is = this.clazz.getResourceAsStream(this.path); } else if (this.classLoader != null) { is = this.classLoader.getResourceAsStream(this.path); } else { is = ClassLoader.getSystemResourceAsStream(this.path); } if (is == null) { throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist"); } return is; }
該方法就是ClassPathResource的getInputStream方法,可以發現其主要通過class類或者ClassLoader來返回InputStream。而之前的分析可知,當loadBeanDefinition時,最終應用的是InputSource inputSource = new InputSource(inputStream);InputSource,屬於org.xml.sax包,是一個XML形式的輸入流。
3.Context元件
Context元件在Spring的org.springframework.context包下,它的作用主要是給Spring提供一個執行時的環境,用以保證各個物件的狀態。其中ApplicationContext是Context的頂級父類介面,它除了繼承一個能表示應用環境的基本資訊介面外,還繼承了5個介面,這5個介面擴充套件了Context的功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver
可以發現其主要應用子類為ClassPathXmlApplicationContext,FileSystemXmlApplicationContext,以及應用在Web上的XmlWebApplicationContext.
二. ApplicationContext原始碼詳解
在ApplicationContext的設計中,一方面可以看到它繼承了BeanFactory介面體系結構的ListableBeanFactory, HierarchicalBeanFactory,具備了IOC容器的基本功能;另一方面,通過繼承MessageSource, ApplicationEventPublisher, ResourcePatternResolver這些介面,使得其被賦予了更高級別的特性。
1.java doc
/** * Central interface to provide configuration for an application. * This is read-only while the application is running, but may be * reloaded if the implementation supports this. * * <p>An ApplicationContext provides: * <ul> * <li>Bean factory methods for accessing application components. * Inherited from {@link org.springframework.beans.factory.ListableBeanFactory}. * <li>The ability to load file resources in a generic fashion. * Inherited from the {@link org.springframework.core.io.ResourceLoader} interface. * <li>The ability to publish events to registered listeners. * Inherited from the {@link ApplicationEventPublisher} interface. * <li>The ability to resolve messages, supporting internationalization. * Inherited from the {@link MessageSource} interface. * <li>Inheritance from a parent context. Definitions in a descendant context * will always take priority. This means, for example, that a single parent * context can be used by an entire web application, while each servlet has * its own child context that is independent of that of any other servlet. * </ul> * * <p>In addition to standard {@link org.springframework.beans.factory.BeanFactory} * lifecycle capabilities, ApplicationContext implementations detect and invoke * {@link ApplicationContextAware} beans as well as {@link ResourceLoaderAware}, * {@link ApplicationEventPublisherAware} and {@link MessageSourceAware} beans. * * @author Rod Johnson * @author Juergen Hoeller * @see ConfigurableApplicationContext * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.core.io.ResourceLoader */
ApplicationContext新增的功能主要表現在 :
1)可以支援不同的資訊源,它擴充套件了MessageSource,支援國際化。
2)訪問資源,主要就是ResourceLoader的繼承,這樣可以從不同地方得到bean定義的資源。
3)支援應用事件,繼承了ApplicationEventPublisher, 這樣在上下文中引入了事件機制。
2.原始碼
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /** * Return the unique id of this application context. * @return the unique id of the context, or {@code null} if none *///返回標誌Context的Id編號 String getId(); /** * Return a name for the deployed application that this context belongs to. * @return a name for the deployed application, or the empty String by default */ //返回context所屬應用名稱 String getApplicationName(); /** * Return a friendly name for this context. * @return a display name for this context (never {@code null}) */ String getDisplayName(); /** * Return the timestamp when this context was first loaded. * @return the timestamp (ms) when this context was first loaded */ //返回loaded時間戳 long getStartupDate(); /** * Return the parent context, or {@code null} if there is no parent * and this is the root of the context hierarchy. * @return the parent context, or {@code null} if there is no parent */ //返回雙親ApplicationContext,證明這裡是有層次關係的 ApplicationContext getParent(); /** * Expose AutowireCapableBeanFactory functionality for this context. * <p>This is not typically used by application code, except for the purpose of * initializing bean instances that live outside of the application context, * applying the Spring bean lifecycle (fully or partly) to them. * <p>Alternatively, the internal BeanFactory exposed by the * {@link ConfigurableApplicationContext} interface offers access to the * {@link AutowireCapableBeanFactory} interface too. The present method mainly * serves as a convenient, specific facility on the ApplicationContext interface. * <p><b>NOTE: As of 4.2, this method will consistently throw IllegalStateException * after the application context has been closed.</b> In current Spring Framework * versions, only refreshable application contexts behave that way; as of 4.2, * all application context implementations will be required to comply. * @return the AutowireCapableBeanFactory for this context * @throws IllegalStateException if the context does not support the * {@link AutowireCapableBeanFactory} interface, or does not hold an * autowire-capable bean factory yet (e.g. if {@code refresh()} has * never been called), or if the context has been closed already * @see ConfigurableApplicationContext#refresh() * @see ConfigurableApplicationContext#getBeanFactory() */ AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; }
3.*****單步除錯ApplicationContext****
仍然採用上一節所使用的例子
ApplicationContext appContext=new ClassPathXmlApplicationContext("beans.xml"); Performer performer=(Performer) appContext.getBean("dancer"); performer.perform();
(1)ApplicationContext appContext=new ClassPathXmlApplicationContext("beans.xml");
呼叫構造器
/** * Create a new ClassPathXmlApplicationContext, loading the definitions * from the given XML file and automatically refreshing the context. * @param configLocation resource location * @throws BeansException if context creation failed */ public ClassPathXmlApplicationContext(String configLocation) throws BeansException { this(new String[] {configLocation}, true, null); }
可以看到除了load xml定義檔案外,還有自動重新整理的作用。
第二個boolean引數,是refresh啟動引數。
/** * Create a new ClassPathXmlApplicationContext with the given parent, * loading the definitions from the given XML files. * @param configLocations array of resource locations * @param refresh whether to automatically refresh the context, * loading all bean definitions and creating all singletons. * Alternatively, call refresh manually after further configuring the context. * @param parent the parent context * @throws BeansException if context creation failed * @see #refresh() */ public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
super(parent),通過逐層向上,最後會到AbstractApplicationContext.
回到上面可以看到refresh()方法即為IOC容器初始化的方法,標誌著IOC容器的啟動。
setConfigLocations(configLocations),設定資源屬性陣列
/** * Set the config locations for this application context. * <p>If not set, the implementation may use a default as appropriate. */ 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] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
(2)refresh()
該方法屬於AbstractApplicationContext,即第一個抽象類。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //呼叫容器準備重新整理的方法,獲取容器的當時時間,同時給容器設定同步標識 ,log資訊也是源自於這個方法 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { 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; } } }
2.1 prepareRefresh();
為重新整理Context前做準備,設定啟動時間,同時Log資訊同樣源自這個方法。
/** * Prepare this context for refreshing, setting its startup date and * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { this.startupDate = System.currentTimeMillis(); this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); }
2.2ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
重新整理所有的BeanFactory子容器,同時這裡涉及到了解析和載入BeanDefinition的步驟。
下面就分析一下BeanFactory的重新整理方法refreshBeanFactory()
這裡應用了委派模式,因為refreshBeanFactory()方法屬於其子類AbstractRefreshApplicationContext.
/** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */ @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId());
//對IoC容器進行定製化,如設定啟動引數,開啟註解的自動裝配等
customizeBeanFactory(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); } }
1.這裡可以看到一個構建DefaultListableBeanFactory容器的過程,先是構造BeanFactory,createBeanFactory()。
2.loadBeanDefinitions(beanFactory),這裡載入了beanDefinition。
接下來再深入loadBeanDefinition(beanFactory)方法
該方法屬於AbstractXmlApplicationContext,又是一個委派模式,讓子類來實現。
/** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */ @Override 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(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); }
1.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 這個與(一)中分析的過程一樣,同樣是建立了一個可以載入BeanDefinition的讀寫器,同樣用DefaultListableBeanFactory作為構造器引數,從而賦予registy屬性。
2.呼叫loadBeanDefinitions()
/** * Load the bean definitions with the given XmlBeanDefinitionReader. * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory} * method; hence this method is just supposed to load and/or register bean definitions. * @param reader the XmlBeanDefinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
最終呼叫reader.loadBeanDefinitions(configLocations);這就又回到了(一)IOC容器初始化的過程。
到這裡就完成了BeanDefinition的載入,註冊工作。並且最終返回了DefaultListableBeanFactory,所以BeanDefinition持有容器依然是DefaultListableBeanFactory.所以接下來的工作就應該是例項化工作。
2.3 prepareBeanFactory(beanFactory);
這是在例項化之前進行的工作。
建立好beanFactory後,新增Spring本身需要的工具類。為容器配備了ClassLoader,PropertyEditor和BeanPostProcessor.
/** * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //....... }
這裡可以看到,ApplicationContextAwareProcessor作為BeanPostProcessor的實現,在這裡新增。
其主要作用是當Bean實現了ApplicationContextAware介面後,當該Bean完成例項化依賴注入之後,會通過BeanPostProcessor的方式來給該Bean注入當前的ApplicationContext.從而使得該例項有能力獲得ApplicationContext.
2.4 postProcessBeanFactory(beanFactory);
這個方法是預留方法,是用來對BeanFactory進行後處理的方法。
2.5 invokeBeanFactoryPostProcessors(beanFactory);
呼叫所有註冊的BeanFactoryPostProcessor的Bean,這裡也是針對BeanFactory的後置處理器的呼叫。
2.6 registerBeanPostProcessors(beanFactory);
BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件,Bean的後置處理器。Register bean processors that intercept bean creation.這個註冊主要是繫結到DefaultListableBeanFactory中取。
後置處理器向容器註冊以後,容器中管理的Bean就具備了接收IoC容器事件回撥的能力。
BeanPostProcessor是一個介面類,主要有兩個方法,一個是postProcessBeforeInitialization,在Bean的初始化前提供回撥入口;另一個是postProcessAfterInitialization,在Bean的初始化後提供回撥入口。實際上,這兩個後置處理器方法是一前一後圍繞著Bean定義的init-method方法呼叫的,都是發生在populateBean()方法之後,即完成依賴注入之後發生的。
上面其實涉及到了兩個Spring的擴充套件點,一個是BeanFactoryPostProcessor和BeanPostProcessor,他們分別在構建BeanFactory和構建Bean物件時呼叫,還有就是InitializationBean和DisposableBean,他們分別在Bean例項建立和銷燬時被呼叫。
2.7 initMessageSource()和 initApplicationEventMulticaster();
初始化資訊源和事件傳播器。
這是由於ApplicationContext分別實現了MessageSource, ApplicationEventPublisher兩個介面。
2.8 finishBeanFactoryInitialization(beanFactory)
完成BeanFactory的初始化工作,這裡涉及到了對於lazy-init屬性的處理。
/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }
最後一個方法preInstantiateSingletons(),看註釋可知例項化所有的單例,non-lazy-init,即lazy-init屬性為false,而由於其預設屬性就是false,所以這裡會例項化所有的單例。
@Override public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { smartSingleton.afterSingletonsInstantiated(); return null; } }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()),從這句程式碼可以看出當BeanDefinition不是抽象類,是單例類,lazyinit屬性為false時,則預例項化,其不為FactoryBean時呼叫getBean()方法。
其BeanDefinition定義如下:Root bean: class [com.wly.source.spring_scoure_inspect.Dancer]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [beans.xml]
所以這裡就完成了預例項化的過程。
2.9 finishRefresh()
初始化容器的生命週期事件處理器,併發布容器的生命週期事件。
/** * Finish the refresh of this context, invoking the LifecycleProcessor's * onRefresh() method and publishing the * {@link org.springframework.context.event.ContextRefreshedEvent}. */ protected void finishRefresh() { // Initialize lifecycle processor for this context. initLife