一、前言
最近在看spring
源码,发现之前看的很多细节已经忘了,于是决定在看源码的过程中也把主要的流程用博客记载下来,希望自己能坚持下来吧。
spring
已经发展很久,整个体系已经变得很庞大了。为了能更好的把源码看下去,我决定从最基础也是最核心的IOC
开始切入,并且从最原始的xml
解析开始看。面对这样一个庞大的体系,我认为从最原始的方式开始学习,才能更好的看懂它的设计和实现思路。
这一系列文章会默认你对于spring
的使用已经熟悉,并且不抗拒读源码。因为很多的文字会在源码片段上注释-对于源码解析的文章,我暂时也找不到更好的表述方法了。
二、一个简单的示例
首先我们配置一个bean
:
<bean class="com.xiaoxizi.spring.service.AccountServiceImpl"
id="accountService" scope="singleton" primary="true"/>
对应的类:
public class AccountServiceImpl implements AccountService {
@Override
public String queryAccount(String id) {
return null;
}
}
测试类:
@Test
public void test1() {
applicationContext = new ClassPathXmlApplicationContext("spring.xml");
AccountService bean = applicationContext.getBean(AccountService.class);
System.out.println(bean);
}
运行结果:
com.xiaoxizi.spring.service.AccountServiceImpl@3e78b6a5
三、源码解析
1. beanDefinition注册流程
我们知道,spring
容器启动的逻辑在refresh()
方法里面。所以,话不多说,直接点进refresh()逻辑,具体位置是 org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
// 本篇博文主要讲这个逻辑
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
...
}
本篇博文主要讲xml解析的逻辑,暂时我们只关注 obtainFreshBeanFactory()
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
继续往下跟refreshBeanFactory()
,实际上方法位置在org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建一个beanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 加载所有的BeanDefinitions,实际解析xml的位置
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
继续往下 org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 这里使用了委托模式,把BeanDefinition的解析委托给了 BeanDefinitionReader
// 由于我们当前是解析xml,所以是委托给Xml...Reader。合理想象,注解方式将会委托给Anno...Reader
// 需要注意的是,我们把beanFactory引用传递给了Reader,之后会用到
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// ... 为BeanDefinitionReader设置了一些不重要的属性,略过。
// 加载BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}
// XmlBeanDefinitionReader对应构造器,注意 beanFactory 是作为 BeanDefinitionRegistry 传入的
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
// 可以看到,是委托给Reader来加载BeanDefinition的
reader.loadBeanDefinitions(configResources);
}
// 配置文件位置实际上就是我们 new ClassPathXmlApplicationContext("xxx") 时传入的
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 可以看到,是委托给Reader来加载BeanDefinition的
reader.loadBeanDefinitions(configLocations);
}
}
经过一系列解析、包装、加载逻辑之后… org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 配置文件的输入流被加载成了Document --> XML解析知识,详细可搜素 SAX解析
Document doc = doLoadDocument(inputSource, resource);
// 解析并注册BeanDefinitions
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
// 异常处理,省略...
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 又来了,熟悉的委托模式,Document的解析被委托给了BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader