欢迎访问我的个人博客休息的风
spring ioc容器的核心类是AbstractApplicationContext,入口方法是refresh。这个方法是个模板方法,定义了加载到容器的全部过程。本篇博客将分析,spring将xml配置文件加载到内存的一个过程。(著名的dubbo分布式框架也利用了spring加载xml的机制,定制自己的xml解析器将对象接入到ioc容器中。)大致过程为:创建beanFactory用于存放转换后的信息->读取文件到输入流中->读取输入流里的数据,用NamespaceHandler里注册的解析器处理返回BeanDefinition->将BeanDefinition保存到DefaultListableBeanFactory的beanDefinitionMap中。
以下是整个调用过程的时序图,最终xml在spring中会放到一个以名称为key,beanDefinition为value的ConcurrentHashMap中。将根据这个时序图,逐步分析对应的源码,希望能把spring加载xml这一过程解释清楚(图象看不清可右击在新页签中查看)
首先,在AbstractApplicationContext.refresh方法中,作为spring初始化的全部过程定义。obtainFreshBeanFactory这个方法是开始解析xml文件的入口
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //省略很多代码。。。。。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //在AbstractRefreshableApplicationContext中去创建DefaultListableBeanFactory类 //这个DefaultListableBeanFactory可以当作是存放ioc容器的地方 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
具体如何创建DefaultListableBeanFactory的,在子类AbstractRefreshableApplicationContext中实现
protected final void refreshBeanFactory() throws BeansException { //是否存在bean工厂类,这个工厂类指的是DefaultListableBeanFactory if (hasBeanFactory()) { //销毁工厂类里面的bean destroyBeans(); //工厂类设置为null closeBeanFactory(); } try { //创建DefaultListableBeanFactory对象 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //设置工厂类一些参数值 customizeBeanFactory(beanFactory); //真正开始加载xml,转换为beandefinition的入口 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } }
在AbstractXmlApplicationContext会去调用loadBeanDefinitions,去读取还是交由XmlBeanDefinitionReader类处理
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. //以bean工厂类为参数创建一个读取器,之后读取的内容还是放到工厂类里 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); //交由beanDefinitionReader去读取文件内容 loadBeanDefinitions(beanDefinitionReader); }
在XmlBeanDefinitionReader类里,会去把文件转换为文件输入流。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { //省略一些代码 try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } }
接下来读取输入流里面的信息,用BeanDefinitionDocumentReader(DefaultBeanDefinitionDocumentReader)的registerBeanDefinitions方去去读取。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //创建文件Document读取器 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); //这里的getRegistry()其实也是获取DefaultListableBeanFactory int countBefore = getRegistry().getBeanDefinitionCount(); //用文件Document读取器读取,并把解析的BeanDefinition放到DefaultListableBeanFactory里 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
在DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions方法里,会去创建BeanDefinitionParserDelegate对象。需要特别关注这个类,因为这个类会去调用对应的NamespaceHandler里面注册的解析器去解析。(dubbo里面DubboNamespaceHandler就是在这里与spring结合在一起的)
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); //省略一些代码。。 preProcessXml(root); //解析xml配置文件里的配置,转换为beanDefinition, // 并用BeanDefinitionReaderUtils注册到DefaultListableBeanFactory里 parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; }
在解析xml的时候,会委托BeanDefinitionParserDelegate去做,这里真正处理xml里面的配置具体内容的,是注册在NamespaceHandler里面的Parser解析器。
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } //这里根据namespaceUri去获取对应的NamespaceHandler去做处理 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
NamespaceHandlerSupport类有对NamespaceHandler抽象的统一处理。通过NamespaceHandlerSupport.findParserForElement方法找到之前注册到NamespaceHandler的BeanDefinitionParser
public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser()); registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser()); registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser()); registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser()); registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser()); registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser()); registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser()); } }
解析之后,将xml里面的数据处理成beanDefinition后,统一通过BeanDefinitionReaderUtils.registerBeanDefinition注册到DefaultListableBeanFactory的beanDefinitionMap中。
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); //这个registry就是DefaultListableBeanFactory //放入到beanDefinitionMap中 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
至此,就将xml配置文件里的配置信息转换为DefaultListableBeanFactory的beanDefinitionMap里面的信息。
开篇讲到的整个过程为:1、创建beanFactory用于存放转换后的信息->2、读取文件到输入流中->3、读取输入流里的数据,用NamespaceHandler里注册的解析器处理返回BeanDefinition->4、将BeanDefinition保存到DefaultListableBeanFactory的beanDefinitionMap中。再回顾下整个代码过程,与开篇的对应如下:
1、在AbstractApplicationContext.refresh这个方法里,作为创建beanFactory的入口。
2、在XmlBeanDefinitionReader.loadBeanDefinitions,会去把文件转换为文件输入流。
3、BeanDefinitionParserDelegate.parseCustomElement这个类的方法会去调用对应的NamespaceHandler里面注册的解析器去解析
4、BeanDefinitionReaderUtils.registerBeanDefinition这个方法里,会把BeanDefinition注册到BeanFactory中