继上篇Spring启动流程(一)
下面的refreshBeanFactory方法的主要工作:加载applicationContext.xml配置文件,创建Spring Bean Definition
@Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }DefaultListableBeanFactory是一个很重要的Bean工厂类,内部存储了bean definition信息,即bean的元数据,即描述bean的信息,这些内容存放在DefaultListableBeanFactory内的不同的容器中(map、list、set);
DefaultListableBeanFactory可以通过后置处理器扩展;
loadBeanDefinitions方法传入DefaultListableBeanFactory,内部是将bean definitions信息设置到bean factory,如何设置呢?会使用不同的bean definition readers来读取配置文件中配置的bean,然后设置到DefaultListableBeanFactory内部的不同数据结构中。
比如常用的XmlBeanDefinitionReader。可以看一下BeanDefinitionReader接口的类继承层次图如下。
1、加载applicationContext.xml配置文件
2、解析xml
3、将xml中的内容转化为Spring Bean Definition。
AbstractBeanDefinitionReader.java
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int count = loadBeanDefinitions(resources);//通过类加载器在classpath下找到applicationContext配置文件的绝对路径DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }依次遍历所有遇到的元素(空行、换行、注释、xml节点),但是只会解析xml节点(node instanceof Element) 。
内部除了namespace是http://www.springframework.org/schema/beans的,其他节点解析都走delegate.parseCustomElement(ele);
@Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } 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)); }这里的namespaceHandler是从META-INF/spring-handlers文件读取的,之后通过反射初始化使用
不过这里不管是通过哪个namespaceHandler,都要通过NamespaceHandlerSupport转发处理,因为所有的namespaceHandler都是继承NamespaceHandlerSupport,重写了init方法,init方法只是建立xml节点属性->BeanDefinitionParser的映射关系。
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { this.parsers.put(elementName, parser); }接着会从这个映射关系里找命名空间处理器然后处理
@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }如果是开启注解的包扫描配置:
<context:component-scan base-package="com.baby.kim">会调用ComponentScanBeanDefinitionParser,将使用@Service,@Controller等注解的对象转为beanDefinition。
其他的Context namespace下的处理器还有
将beanDefinition信息保存到DefaultListableBeanFactory的属性中。
this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName);总结:
这一篇主要介绍了Spring是如何解析和将在bean definition到bean factory中的,
下一篇Spring启动流程(三)之Bean的实例化将介绍Bean的实例化过程