本篇我們一起來簡單的看一下Spring Framework IoC容器啟動停止。我們從上一篇的代碼入手:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eleven.thinking.in.spring.ioc.overview.container;
import org.eleven.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
/**
* 注解能力 {@link ApplicationContext} 作為 IoC 容器示例
*
* @author <a href="mailto:[email protected]">eleven</a>
* @since
*/
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
public static void main(String[] args) {
// 建立 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将目前類 AnnotationApplicationContextAsIoCContainerDemo 作為配置類(Configuration Class)
applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
// 啟動應用上下文
applicationContext.refresh();
// 依賴查找集合對象
lookupCollectionByType(applicationContext);
// 關閉應用上下文
applicationContext.close();
}
/**
* 通過 Java 注解的方式,定義了一個 Bean
*/
@Bean
public User user() {
User user = new User();
user.setId(1L);
user.setName("eleven");
return user;
}
private static void lookupCollectionByType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("查找到的所有的 User 集合對象:" + users);
}
}
}
我們從applicationContext.refresh();這行代碼如下,applicationContext的這個方法refresh()翻譯過來是重新整理的意思,其實這裡就是建立整個應用上下文的入口,主要代碼如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
/**
* 1.重新整理預處理
*/
// Prepare this context for refreshing.
prepareRefresh();
/**
* 2.閱讀XML中的資訊,注冊BeanDefinition
* obtainFreshBeanFactory 擷取 beanFactory 執行個體并且完成BeanDefinition的注冊工作
*/
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/**
* 3.beanFactory 加載應用上下文中的内建Bean和非Bean對象
*/
prepareBeanFactory(beanFactory);
try {
// 4. Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
/**
* 執行bean後場處理器,執行完畢
* 解析BeanDefinition對象,put到map裡
* 再次執行bean後置工廠處理器
*/
// 5. Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 6. Register bean processors that intercept bean creation.
//注冊bean的後置處理器來友善攔截bean的建立
registerBeanPostProcessors(beanFactory);
// 7.Initialize message source for this context.
initMessageSource();
// 8.Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 9.Initialize other special beans in specific context subclasses.
onRefresh();
// 10.Check for listener beans and register them.
registerListeners();
// 11.建立單執行個體業務Bean(非懶加載單例bean)
// 服務啟動的時候,就會初始化所有的單例bean
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 12.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();
}
}
}
啟動的步驟如下:
- 重新整理預處理;
- 閱讀XML中的資訊,注冊BeanDefinition;
- beanFactory 加載應用上下文中的内建Bean和非Bean對象;
- 執行beanFactory後處理器;
- 執行bean後處理器;
- 注冊bean的後置處理器來友善攔截bean的建立;
- Initialize message source for this context;
- Initialize event multicaster for this context;
- Initialize other special beans in specific context subclasses;
- Check for listener beans and register them;
- 建立單執行個體業務Bean(非懶加載單例bean);
- 完成建立.
另外一方面我們再來看一下停止的方法,代碼如下:
@Override
public void destroySingletons() {
super.destroySingletons();
updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
clearByTypeCache();
}
停止的步驟如下:
- 銷毀所有的Bean對象;
- 銷毀相關的容器。