1.概要
簡単に言えば、IOCコンテナーの初期化プロセスはrefresh()
メソッドによって開始されます。つまり、IOCコンテナーの正式な開始です。具体的には、このスタートアップには、主にBeanDefinitionリソースの配置、ロード、および登録の3つのプロセスが含まれます。
2. IOC起動プロセスの説明
- 最初のプロセスは、リソース配置プロセスです。このリソース配置は、BeanDefinitionのリソース配置を指します(たとえば、Springプロジェクトで通常構成するさまざまなXML構成は、リソースリソースとして統合および抽象化されます)。これは、統合されたResourceインターフェースを介してResourceLoaderによって実行されます。使用により、統一されたインターフェースが提供されます。
- 2番目のプロセスは、BeanDefinitionのロードプロセスです。ロードプロセスでは、ユーザー定義のBeanをIOCコンテナ内のデータ構造、つまりBeanDefinitionとして表します。BeanDefinitionは、実際にはIOCコンテナ内のPOJOオブジェクトを抽象化したものであり、BeanDefinitionによって定義されたデータ構造を通じて、IOCコンテナはPOJOオブジェクト、つまりBeanオブジェクトを簡単に管理できます。
- 3番目のプロセスは、IOCでのBeanDefinitionの登録プロセスです。このプロセスは、主にBeanDefinitionRegistryインターフェースを介して実現されます。登録プロセスは、ロードプロセス中に解析されたBeanDefinitionをIOCコンテナに登録することです。実際、IOCは内部的に解析されたBeanDefinitionをHashMapに注入し、IOCコンテナはこのHashMapを通じてこれらのBeanDefinitionデータを保持します。
3.ソースコード分析
FileSystemXmlApplicationContextを例にすると、コアとなる継承関係は次のとおりです。
サンプルコードは次のとおりです。
FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:bean.xml")
上記のコード行を実行すると、IOCのリソースの配置、解析、および登録プロセスが完了するので、上記のコードのコア実行フローを分析してみましょう。
/**
* Create a new FileSystemXmlApplicationContext, loading the definitions
* from the given XML file and automatically refreshing the context.
* @param configLocation file path
* @throws BeansException if context creation failed
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
私たちが選択するコンストラクタは、リソースファイルパスを渡すことです。実際に呼び出される内部コンストラクタは次のとおりです。
/**
* Create a new FileSystemXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of file paths
* @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 FileSystemXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 父容器设置
super(parent);
// 设置资源访问路径
setConfigLocations(configLocations);
// 刷新启动容器
if (refresh) {
refresh();
}
}
refresh()
メソッドを実行すると、ApplicationContextアドバンストコンテキストコンテナーが作成され、refresh()
メソッド領域に入って特定の実行ロジックを表示します。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 刷新启动前的准备工作
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取Beanfatory->资源的定位和解析就是在此方法中执行的
//(1)AbstractApplicationContext#obtainFreshBeanFactory()
//(2)AbstractApplicationContext#refreshBeanFactory()实际执行子类
//(3)AbstractRefreshableApplicationContext#refreshBeanFactory()的方法
创建DefaultListableBeanFactory并loadBeanDefinitions`
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 配置BeanFactory标准Context特征,比如 classloader,后置处理等。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 允许添加BeanFactoryProcessor来修改beanFactory,子类覆盖方法做额外处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 回调 上面收集到的所有的 BeanFactoryProcessor 了
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean的处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 国际化相关的初始化
initMessageSource();
// Initialize event multicaster for this context.
// 初始化应用事件的广播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 留给子类Context实现一些特殊处理的模板方法(模板方法留给子类实现)
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) {
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();
}
}
}