Processo de inicialização do contêiner Spring
Spring tem duas etapas muito importantes no processo de inicialização: inicialização e atualização do contêiner.
Processo de inicialização
- Se você deseja gerar objetos bean, você precisa de uma fábrica beanFactory (DefaultListableBeanFactory)
- Se você deseja ler uma classe com anotações específicas (como @Service, @Repository) e convertê-la em um objeto BeanDefinition (BeanDefinition armazena todas as informações características do objeto bean, como se é um singleton, se é carregamento lento , factoryBeanName, etc.), então você precisa de um leitor de configuração de anotação (AnnotatedBeanDefinitionReader)
- Se você deseja verificar o diretório do pacote especificado pelo usuário para localizar objetos bean, você precisa de um scanner de caminho (ClassPathBeanDefinitionScanner)
Ao carregar o arquivo de configuração, o Spring cria uma fábrica BeanFactory, depois preenche o BeanDefinition da fábrica com informações de configuração e cria instâncias Bean relacionadas com base nessas informações. Ao criar uma instância do Bean, o Spring adota uma estratégia de inicialização lenta, ou seja, só será inicializado quando a instância do Bean for necessária.
O processo de registro do BeanDefinition inclui principalmente a análise de arquivos de configuração, verificação de anotações, análise de Java Config, etc. Ao analisar o arquivo de configuração, o Spring irá analisá-lo de acordo com as regras de sintaxe do arquivo de configuração e encapsular o resultado da análise em um objeto BeanDefinition. Ao verificar as anotações, o Spring verificará as classes no pacote especificado e encapsulará as classes com as anotações especificadas em objetos BeanDefinition. Ao analisar o Java Config, o Spring irá analisá-lo de acordo com as regras de sintaxe do arquivo de configuração do Java Config e encapsulará o resultado da análise em um objeto BeanDefinition.
ClassPathBeanDefinitionScanner é uma classe de ferramenta da estrutura Spring que pode procurar beans no caminho do pacote especificado. Ele verifica todas as classes elegíveis e as registra como beans para uso em operações subsequentes. Usando esta classe de ferramenta, você primeiro criará um objeto BeanDefinitionRegistry, depois criará um objeto ClassPathBeanDefinitionScanner e definirá seu caminho de verificação e filtro. Finalmente, chame o método scan para iniciar a digitalização. Após a conclusão da verificação, ClassPathBeanDefinitionScanner registrará automaticamente as classes digitalizadas no BeanDefinitionRegistry. Após concluir o registro, você pode usar o BeanFactory do Spring para obter o bean especificado.
processo de atualização
refresh() é usado principalmente para atualizar contêineres. Cada contêiner no Spring chamará o método refresh() para atualizar. O método refresh() conclui principalmente as seguintes etapas:
(1) Prepare o contêiner, como inicializar variáveis de ambiente, registrar ouvintes de eventos do sistema, etc.
(2) Crie ou obtenha uma instância BeanFactory. Se uma instância BeanFactory for transmitida durante a criação, essa instância será usada; caso contrário, uma nova instância BeanFactory será criada com base no arquivo de configuração.
(3) Faça algumas configurações necessárias para BeanFactory, como configurar ClassLoader, configurar BeanPostProcessor, etc.
(4) O pós-processamento do BeanFactory pode ser usado para estender as funções do BeanFactory.
(5) Execute a classe de implementação da interface BeanFactoryPostProcessor para realizar o pós-processamento no BeanFactory.
(6) Registre todas as classes de implementação do BeanPostProcessor.
(7) Inicialize o MessageSource para processamento de internacionalização.
(8) Inicialize o transmissor de eventos para enviar e receber eventos.
(9) Notifique todos os contêineres ouvintes registrados de que foram inicializados.
(10) Liberar recursos ao fechar o container.
(11) Registre o ouvinte de eventos.
(12) Conclua a inicialização do BeanFactory, incluindo criação de instâncias, injeção de dependências, execução de métodos de inicialização, etc.
(13) Conclua a inicialização do contêiner, libere recursos, etc.
//refresh()的简略源码:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 刷新前的预处理
prepareRefresh();
// 2. 获取 beanFactory,即前面创建的【DefaultListableBeanFactory】
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 预处理 beanFactory,向容器中添加一些组件
prepareBeanFactory(beanFactory);
try {
// 4. 子类通过重写这个方法可以在 BeanFactory 创建并与准备完成以后做进一步的设置
postProcessBeanFactory(beanFactory);
// 5. 执行 BeanFactoryPostProcessor 方法,beanFactory 后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessors,bean 后置处理器
registerBeanPostProcessors(beanFactory);
// 7. 初始化 MessageSource 组件(做国际化功能;消息绑定,消息解析)
initMessageSource();
// 8. 初始化事件派发器,在注册监听器时会用到
initApplicationEventMulticaster();
// 9. 留给子容器(子类),子类重写这个方法,在容器刷新的时候可以自定义逻辑,web 场景下会使用
onRefresh();
// 10. 注册监听器,派发之前步骤产生的一些事件(可能没有)
registerListeners();
// 11. 初始化所有的非单实例 bean
finishBeanFactoryInitialization(beanFactory);
// 12. 发布容器刷新完成事件
finishRefresh();
}
catch(){
...}
finally{
...}
}
}