Spring的核心功能就是IOC和AOP。
IOC分兩個過程:bean的解析注冊 和 bean的執行個體化。
AOP是面向切面程式設計,但是它也離不開bean的解析注冊。
本篇主要講解,容器初始化時候的refresh()方法裡的,幾個重要方法的基本作用。
首先來看一下refresh()方法。spring容器的啟動,建立bean,bean的初始化等一系列過程都在這個refresh方法裡面,進行調用。接下來,對每個方法的作用做一個簡要的說明。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//bean的解析注冊
// 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);//初始化非懶加載的bean
// Last step: publish corresponding event.
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();
}
}
}
1.prepareRefresh()方法
設定spring上下文的重新整理時間,并将active設為true,初始化一些容器啟動必要的資源。我們可以看到,這個方法裡面是打了日志的,在我debug的時候,我的日志列印如下:
[INFO][main][2017-07-03 11:56:40][org.springframework.context.support.AbstractApplicationContext] - Refreshing org[email protected]7fac631b: startup date [Mon Jul 03 11:56:40 CST 2017]; root of context hierarchy
protected void prepareRefresh() {
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
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
2.invokeBeanFactoryPostProcessors()
beanFactoryPostprocessor的作用是在beanFactory初始化之後提供一個修改的機會。spring已經提供了不少實作,我們自己也可以寫一些實作配置在xml中 或者手動調用。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}
對于它的講解,另外的兩個部落格,我覺得很好
http://www.jianshu.com/p/0e7f65afa156
http://blog.csdn.net/lsm135/article/details/53300912
3.obtainFreshBeanFactory()方法
obtainFreshBeanFactory()方法,是進行bean的解析注冊的地方。所謂bean的解析注冊就是指 将xml中配置的bean,轉化為Java對象的BeanDefinition,并将它們儲存在容器的map裡。傳回的beanFactory裡面,就攜帶着存放beanName和BeanDefinition的map。
在這個方法執行完畢後,BeanDefinitionMap裡面就存放着beanName和beanDefinition的對應資訊。而這個時候,存放beanName和執行個體化bean對象的singletonObjections仍然為空。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcBnVtpFbsdkWxg2VapXNXl1csdkYwZlMkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jM3cTOwATMyEzMwcDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
這個方法對應着1,2
4.finishBeanInitialization(beanFactory)
這個方法裡面,用來初始化非懶加載的bean。并非所有bean都在容器啟動的時候執行個體化。在xml中配置bean的時候,有個lazy-ini屬性,預設為false。是以預設情況下,單例的非懶加載的bean在容器啟動的時候會執行個體化。如果是懶加載的,那麼在getBean的時候,再執行個體化。
具體來說:
Spring什麼時候執行個體化bean,首先要分2種情況
第一:如果你使用BeanFactory作為Spring Bean的工廠類,則所有的bean都是在第一次使用該Bean的時候執行個體化
第二:如果你使用ApplicationContext作為Spring Bean的工廠類,則又分為以下幾種情況:
(1):如果bean的scope是singleton的,并且lazy-init為false(預設是false,是以可以不用設定),則ApplicationContext啟動的時候就執行個體化該Bean,并且将執行個體化的Bean放在一個map結構的緩存中,下次再使用該Bean的時候,直接從這個緩存中取
(2):如果bean的scope是singleton的,并且lazy-init為true,則該Bean的執行個體化是在第一次使用該Bean的時候進行執行個體化
(3):如果bean的scope是prototype的,則該Bean的執行個體化是在第一次使用該Bean的時候進行執行個體化
在我工程的Demo裡,是通過ClassPathXmlApplicationContext擷取xml的。是以屬于通過ApplicationContext擷取bean,它的預設BeanFactory是DefaultListableBeanFactory。
最後通過這個圖,可以大概了解整個流程: