先从源码来看 spring 的 IOC 都经历了哪些方法:
1.开始加载 xml 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
2.ApplicationContext 的构造方法
this(new String[] {configLocation}, true, null);
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
3.父类构造方法
一直跳转到 AbstractApplicationContext 文件
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
其中 this()方法是创建一个新的 AbstractApplicationContext,并生成一个默认的资源模式解析器。因为 parent 为 null,所以 setParent 没有实质作用。
4.设置配置文件路径
返回 ClassPathXmlApplicationContext 查看 setConfigLocations 方法。此方法是将传入的资源路径保存下来。
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
5.refresh 方法
主要的 IOC 方法。主要看 spring 的 beanfactory 怎么生成的,以及保存了什么。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备在这种情况下使用的Bean工厂。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用工厂处理器在上下文中注册为bean。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean处理器,拦截bean创建。
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// 初始化此上下文的消息源。
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其他特殊bean。
onRefresh();
// Check for listener beans and register them.
registerListeners();
// 检查侦听器bean并注册它们。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
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();
}
}
}
6.obtainFreshBeanFactory 方法
在 refreshBeanFactory 生成 beanFactory,然后通过 getBeanFactory 获取
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
7.refreshBeanFactory 的实现方法
在 idea 中可以使用 ctrl+alt+b 的快捷键查看方法的实现方法。该方法在 AbstractRefreshableApplicationContext 中,
可以看到,方法中先销毁了之前的 beanFactory(如果有的话),然后生成了一个默认的 DefaultListableBeanFactory。然后将 beanFactory 保存,使得上一步的 getBeanFactory 可以获取。然后看 loadBeanDefinitions 方法。
8.doLoadBeanDefinitions 方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//使用前面封装的资源文件和inputSource读取资源文件,并封装为Document对象
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
9.registerBeanDefinitions 方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建一个BeanDefinition读取器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
10.doRegisterBeanDefinitions
14.registerBeanDefinition
终于结束了,可以看到,最后将 beanDefinition 存放在了 beanDefinitionMap 中,而 beanDefinitionMap 就是一个 ConcurrentHashMap 集合。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于