1. Visão geral
Simplificando, o processo de inicialização do contêiner do IOC é refresh()
iniciado por um método, o que significa o início oficial do contêiner do IOC. Especificamente, essa inicialização inclui principalmente os três processos de posicionamento, carregamento e registro do BeanDefinition Resource.
2. Descrição do processo de inicialização do COI
- O primeiro processo é o processo de posicionamento de recursos. Esse posicionamento de recurso refere-se ao posicionamento de recurso de BeanDefinition (por exemplo, as várias configurações XML que geralmente configuramos no projeto Spring são unificadas e abstraídas como recursos de recurso), concluídas pelo ResourceLoader por meio de uma interface de recurso unificada. Use fornece uma interface unificada.
- O segundo processo é o processo de carregamento do BeanDefinition. O processo de carregamento é representar o Bean definido pelo usuário como a estrutura de dados dentro do contêiner IOC, ou seja, BeanDefinition. Na verdade, o BeanDefinition é a abstração dos objetos POJO no contêiner IOC.Por meio da estrutura de dados definida pelo BeanDefinition, o contêiner IOC pode gerenciar facilmente os objetos POJO, ou seja, os objetos Bean.
- O terceiro processo é o processo de registro do BeanDefinition no IOC. Esse processo é alcançado principalmente através da interface BeanDefinitionRegistry. O processo de registro é registrar o BeanDefinition analisado durante o processo de carregamento no contêiner IOC. De fato, o IOC injeta internamente o BeanDefinition analisado em um HashMap, e o contêiner do IOC mantém esses dados do BeanDefinition por meio desse HashMap.
3. Análise do código fonte
FileSystemXmlApplicationContext como exemplo, o relacionamento principal de herança é:
O código de exemplo é:
FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:bean.xml")
Quando executamos a linha de código acima, o processo de posicionamento, análise e registro de recursos de um COI é concluído.Vamos analisar o fluxo de execução principal do código acima.
/**
* 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);
}
O construtor que escolhemos é transmitir um caminho de arquivo de recurso, e o construtor interno realmente chamado é:
/**
* 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();
}
}
Quando executamos o refresh()
método, nosso container de contexto avançado ApplicationContext foi criado, entramos na refresh()
área do método para visualizar a lógica de execução específica:
@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();
}
}
}