spring 源码学习笔记(一)—— spring ioc 之加载XML转换为BeanDefinition

来源:互联网 发布:u盘windows无法格式化 编辑:程序博客网 时间:2024/05/19 22:50

欢迎访问我的个人博客休息的风

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文件的入口

@Overridepublic 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();      //省略很多代码。。。。。


在进入到obtainFreshBeanFactory方法里,可以看到,这是创建DefaultListableBeanFactory的入口,这个DefaultListableBeanFactory可以当作是存放ioc容器的地方。

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();      }   }

接下来读取输入流里面的信息,用BeanDefinitionDocumentReaderDefaultBeanDefinitionDocumentReader的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中



原创粉丝点击