最近用spring的时候感觉不怎么了解内部原理,用起来有些不习惯,于是找空看了一下spring的源码,看了一下bean加载的流程以及调用流程,现总结如下:
加载
contextLoaderListener->ContextLoader.initWebApplicationContext,调用本对象的createWebApplicationContext->ConfigurableWebApplicationContext.refresh()->AbstractApplicationContext.refresh();
在上面的refresh里面有
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
追踪这段代码,发现调用了:AbstractRefreshableApplicationContext的以下方法:
protected final void refreshBeanFactory()
throws BeansException
{
if(hasBeanFactory())
{
destroyBeans();
closeBeanFactory();
}
try
{
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized(beanFactoryMonitor)
{
this.beanFactory = beanFactory;
}
}
catch(IOException ex)
{
throw new ApplicationContextException((new StringBuilder("I/O error parsing bean definition source for ")).append(getDisplayName()).toString(), ex);
}
}
这个方法里面有一句很重要: loadBeanDefinitions(beanFactory);
这一句的作用是从配置文件加载所有的BeanDefinition.
项目中用到的是基于xml的spring配置方式,所以最终的工厂类是:XmlWebApplicationContext。
加载beandefinition时,把逐个文件用XmlBeanDefinitionReader进行解析并加载bean。
XmlBeanDefinitionReader首先把每个配置文件载入成一个w3c的Document对象,然后 用 BeanDefinitionDocumentReader解析Document.
BeanDefinitionDocumentReader的实现类是DefaultBeanDefinitionDocumentReader。
实现类加载bean的方法如下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
{
if(delegate.isDefaultNamespace(delegate.getNamespaceURI(root)))
{
NodeList nl = root.getChildNodes();
for(int i = 0; i < nl.getLength(); i++)
{
org.w3c.dom.Node node = nl.item(i);
if(node instanceof Element)
{
Element ele = (Element)node;
String namespaceUri = delegate.getNamespaceURI(ele);
if(delegate.isDefaultNamespace(namespaceUri))
parseDefaultElement(ele, delegate);
else
delegate.parseCustomElement(ele);
}
}
} else
{
delegate.parseCustomElement(root);
}
}
方法中的Element对象root其实就是之前的Document,是一个顶级的Element。
然后再通过BeanDefinitionParserDelegate解析这个root下面的每个Element,看看是不是下级Element,如果是,
判断Element是不是默认namespace(比如:beans-这个是默认,security,aop等),如果是:
调用parseDefaultElement(ele, delegate);否则调用delegate.parseCustomElement(ele)。
BeanDefinitionParserDelegate是一个很核心的类,这个类完成对bean对应的element的构造函数,bean参数,
bean的fields的解析并且分别进行保存,之后生成bean的实例的时候需要从中取出这些信息来生成bean实例。
parseCustomElemen方法的主要作用就是根据namespace调用对用的Namespacehandler解析element并且做 相应的操作(比如:securitynamespacehandler的作用是为应用根据security配置文件添加相应的filter).现在主要集中 在parseDefaultElement 方法上面,这个方法是提取bean的关键方法。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
{
if(delegate.nodeNameEquals(ele, "import"))
importBeanDefinitionResource(ele);
else
if(delegate.nodeNameEquals(ele, "alias"))
processAliasRegistration(ele);
else
if(delegate.nodeNameEquals(ele, "bean"))
processBeanDefinition(ele, delegate);
}
对于在默认namespace下面的常用标签:import,alias,bean,上面的方法都做了处理。下面主要跟踪一下常用的bean的解析: processBeanDefinition。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
{
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null)
{
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try
{
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch(BeanDefinitionStoreException ex)
{
getReaderContext().error((new StringBuilder("Failed to register bean definition with name '")).append(bdHolder.getBeanName()).append("'").toString(), ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
至此,真正执行bean解析工作的类出来了:BeanDefinitionParserDelegate 。此类解析Element并且返回一个
BeanDefinitionHolder 对象。然后通过
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
支持,把BeanDefinition注册到了beanfactory里面。下面的工作就是取出bean了。
bean的获取
一个常用的方式是通过ApplicationContext接口来获取bean。getBean(String name)的实现类是AbstractApplicationContext。追踪代码,最终发现bean的获取着落在AbstractBeanFactory的doGetBean方法上。继续跟踪,可以跟踪到:AbstractAutowireCapableBeanFactory的doCreateBean方法(对于Prototype的bean),此方法的作用是创建bean的实例。跟踪以上方法,发现是依靠InstantiationStrategy来实例化bean。
有两张策略来实例化bean: SimpleInstantiationStrategy,CglibSubclassingInstantiationStrategy。从名字上很容易看出,前者是不用代理的实例化,后者是通过cglib生成代理类对象的实例化。
至此,bean的取出过程也大概清楚了。因为时间仓促,很多细节来不及描述,等有空了补全这篇文章。