前言
先來回顧一下創(chuàng)建Spring IOC容器的兩種方式:
- 通過BeanFactory創(chuàng)建;
- 通過ApplicationContext創(chuàng)建芹壕;
其中ApplicationContext又可以分為XML和Annotation兩種形式丐谋,Annotation形式以AnnotationConfigApplicationContext
子類為代表。
BeanFactory繼承結(jié)構(gòu)
- AutowireCapableBeanFactory接口定義IOC容器的自動(dòng)裝配功能,在ApplicationContext類中可以通過
getAutowireCapableBeanFactory()
獲取該接口膀跌,從而使得ApplicationContext擁有自動(dòng)裝配功能; -
Hierarchical
的意思是"分級(jí)"固灵,所以HierarchicalBeanFactory
允許應(yīng)用啟動(dòng)多個(gè)BeanFactory并設(shè)置父子關(guān)系捅伤。例如Spring+SpringMVC應(yīng)用中的父子容器; -
ListableBeanFactory
中定義獲取多個(gè)Bean的方法巫玻,而BeanFactory中只定義了獲取單個(gè)Bean的方法丛忆。 - ApplicationContext繼承了BeanFactory,同時(shí)擁有了
AutowireCapableBeanFactory
仍秤、HierarchicalBeanFactory
熄诡、ListableBeanFactory
三個(gè)接口定義的功能。 -
ConfigurableBeanFactory
接口定義了ioc容器的可定制性诗力,它定義了設(shè)置類裝載器凰浮,屬性編輯器,容器初始化后置處理器等方法苇本;幾乎所有的beanFactory都會(huì)實(shí)現(xiàn)這個(gè)接口袜茧,賦予了BeanFactory可擴(kuò)展的功能。
ApplicationContext繼承結(jié)構(gòu)
- ApplicationContext分為web環(huán)境類和非web環(huán)境類瓣窄,如果要在WEB容器中創(chuàng)建IOC需要使用WebApplicationContext的實(shí)現(xiàn)類笛厦。
-
FileSystemXmlApplicationContext
和ClassPathXmlApplicationContext
類都是通過XML文件創(chuàng)建IOC容器,不同的是要加載的文件位置不同康栈,前者位于文件系統(tǒng)中递递,后者位于classpath當(dāng)中。 -
AnnotationConfigApplicationContext
是基于注解的形式來創(chuàng)建IOC容器啥么,采用java配置文件登舞。
我們將通過Spring(具體版本為:4.3.9.RELEASE)注解的方式來分析IOC容器的創(chuàng)建過程,主要通過AnnotationConfigApplicationContext
類悬荣。入口程序如下
@Test
public void test(){
AnnotationConfigApplicationContext applicationContext = new
AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("IOC容器創(chuàng)建完畢");
Object person = applicationContext.getBean("person");
Person person1 = applicationContext.getBean(Person.class);
System.out.println(person == person1);
}
其中MainConfig
是Spring的注解配置類菠秒,其代碼如下
@Configuration
public class MainConfig {
/**
* @Bean注解的value屬性用來定義注冊(cè)到IOC容器中的bean name
* 如果不指定value屬性,則用方法名作為bean name
* @return
*/
@Bean(value = "person")
public Person getPerson(){
Person person = new Person();
person.setName("Jerry");
person.setAge(18);
person.setNickName("J");
return person;
}
}
AnnotationConfigApplicationContext的繼承體系
由上圖可知,
AnnotationConfigApplicationContext
是ApplicationContext
接口某個(gè)具體實(shí)現(xiàn)類践叠,而ApplicationContext
是BeanFactory
的子接口言缤。所以我們可以將AnnotationConfigApplicationContext
看成是一種BeanFactory
,他們的本質(zhì)都是一樣的禁灼。
ApplicationContext和BeanFactory都是用于加載Bean的管挟,這兩個(gè)類都可以看成是Spring IOC容器,但是ApplicationContext比BeanFactory提供了更多的擴(kuò)展功能弄捕。
常見的ApplicationContext
上圖中用紅框框起來的是一些常見的
ApplicationContext
僻孝,它們用于各種不同的場(chǎng)景。在這些類實(shí)例化的過程中守谓,都會(huì)直接或間接的調(diào)用AbstractApplicationContext.refresh()
方法穿铆。而AbstractApplicationContext.refresh()
方法的執(zhí)行過程就是IOC容器的創(chuàng)建過程。下面來分析一下refresh()方法的執(zhí)行過程斋荞。
refresh()執(zhí)行流程
refresh()
方法很重要荞雏,它是各種IOC容器初始化的入口。首先需要知道的是refresh()
方法運(yùn)用了“模板方法”的設(shè)計(jì)模式平酿,后面會(huì)出個(gè)專欄分析Spring中運(yùn)用的設(shè)計(jì)模式凤优。先來看看refresh()
的源碼
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 準(zhǔn)備上下文信息
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2. 初始化BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 對(duì)BeanFactory進(jìn)行功能填充
prepareBeanFactory(beanFactory);
try {
// 4. 子類覆蓋的方法,用于做特殊的處理,這是個(gè)鉤子方法
postProcessBeanFactory(beanFactory);
// 5. 激活各種BeanFactoryPostProcessor處理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注冊(cè)各種Bean的后置處理器染服,后置處理器的調(diào)用發(fā)生在getBean
registerBeanPostProcessors(beanFactory);
// 7. 國(guó)際化處理
initMessageSource();
// 8. 在容器中初始化消息廣播器
initApplicationEventMulticaster();
// 9. 子類覆蓋的方法别洪,各?類來初始化其他的bean叨恨,鉤子方法
onRefresh();
// 10. 注冊(cè)Listener到消息廣播器中
registerListeners();
// 11. 初始化剩余的所有非懶加載的單實(shí)例bean
finishBeanFactoryInitialization(beanFactory);
// 12. 發(fā)送ContextRefreshEvent廣播柳刮,完成刷新過程
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...
// 13. 清除緩存
resetCommonCaches();
}
}
}
refresh()
正常執(zhí)行完畢,即表明創(chuàng)建好IOC容器痒钝。分析源碼可以知道refresh()
方法做了13件事秉颗。
- 準(zhǔn)備上下文信息;
- 創(chuàng)建BeanFactory送矩;
- 對(duì)BeanFactory進(jìn)行功能填充蚕甥;
- 子類覆蓋的方法,用于做特殊的處理,這是個(gè)鉤子方法栋荸;
- 激活各種BeanFactoryPostProcessor處理器菇怀;
- 注冊(cè)各種Bean的后置處理器,后置處理器的調(diào)用發(fā)生在getBean晌块;
- 國(guó)際化處理爱沟;
- 在容器中初始化消息廣播器;
- 子類覆蓋的方法匆背,各?類來初始化其他的bean呼伸,鉤子方法;
- 注冊(cè)Listener到消息廣播器中钝尸;
- 初始化剩余的所有非懶加載的單實(shí)例bean括享;
- 發(fā)送ContextRefreshEvent廣播搂根,完成刷新過程;
- 清除緩存铃辖。
1. 準(zhǔn)備上下文信息
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 初始化property資源剩愧,擴(kuò)展點(diǎn),留給子類實(shí)現(xiàn)
initPropertySources();
// 驗(yàn)證需要的配置文件是否加載到環(huán)境中
// 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. 創(chuàng)建BeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
這個(gè)方法執(zhí)行完畢之后娇斩,ApplicationContext
就擁有了BeanFactory
的功能隙咸。這段代碼做了兩件事:2.1 初始化BeanFactory;2.2 獲取BeanFactory成洗。
2.1 初始化BeanFactory
refreshBeanFactory();
用來初始化BeanFactory
五督,它最終調(diào)用的是GenericApplicationContext.refreshBeanFactory()
方法,代碼如下:
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());
}
主要是通過getId()方法給BeanFactory設(shè)置serializationId的屬性值瓶殃,此處設(shè)置的值為:"org.springframework.context.annotation.AnnotationConfigApplicationContext@6cc7b4de"
2.2 獲取BeanFactory
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
此處返回的是DefaultListableBeanFactory
3. 對(duì)BeanFactory進(jìn)行功能填充
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));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// 增加對(duì)AspectJ的支持
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 添加默認(rèn)的系統(tǒng)環(huán)境Bean
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
此方法是對(duì)BeanFactory
進(jìn)行一些設(shè)置充包。關(guān)于這一塊的解說可以參考容器的功能擴(kuò)展(二)功能擴(kuò)展
4. postProcessBeanFactory
postProcessBeanFactory
方法是一個(gè)擴(kuò)展點(diǎn),在AbstractApplicationContext
中是一個(gè)空方法遥椿,它主要是讓子類可以重寫以實(shí)現(xiàn)它們自己的特殊邏輯基矮。而AnnotationConfigApplicationContext
并沒有對(duì)該類進(jìn)行重寫。
5.激活各種BeanFactoryPostProcessor處理器
BeanFactoryPostProcessor
和BeanPostProcessor
都是Spring提供的擴(kuò)展點(diǎn)冠场,可以通過它們對(duì)bean的定義修改家浇。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
激活BeanFactoryPostProcessor
的工作會(huì)委托給PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
進(jìn)行處理。
6. 注冊(cè)各種Bean的后置處理器
Bean的后置處理器的方法也是委托給PostProcessorRegistrationDelegate
處理碴裙,具體方法為:registerBeanPostProcessors()
钢悲。這?只是注冊(cè),真正的調(diào)?是在getBean的時(shí)候
待續(xù)