spring框架刚出来的时候,我们基本都是在 xml文件里配置bean的,那么spring框架是如何解析xml 里内容的呢,今天我们就从一句代码着手,一步步来分析。
spring框架的其中一大特性IOC,讲的就是把bean的创建交给spring框架来做,这样能保证类之间互相引用时,不需要 new 一个对象,只需要使用注解注入即可引用对应的类。因此spring框架会把xml里定义的bean实例化。
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("bean.xml"))
首先看 new ClassPathResource("bean.xml") 做了什么。
public ClassPathResource(String path) { this(path, (ClassLoader) null); } public ClassPathResource(String path, @Nullable ClassLoader classLoader) { Assert.notNull(path, "Path must not be null"); //对 path 进行修正,比如把 "\\" 转为 "/" String pathToUse = StringUtils.cleanPath(path); if (pathToUse.startsWith("/")) { pathToUse = pathToUse.substring(1); } this.path = pathToUse;
//获取当前线程的 ClassLoader this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); }
这句代码把配置文件封装为 ClassPathResource,以便于读取。
接下来是 new XmlBeanFactory
//根据提供的resource 加载 bean definition public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
//parentBeanFactory 初始值为空 super(parentBeanFactory);
//这句才是重点,reader指的是 XmlBeanDefinitionReader
this.reader.loadBeanDefinitions(resource);
}
XmlBeanDefinitionReader 的 loadBeanDefinitions
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//把 Resource 转为 EncodedResource,用于对资源文件编码处理,当设置了编码属性,spring 会使用相应的编码作为输入流的编码。 return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } 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(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
doLoadBeanDefinitions,我删除了一些不重要的catch
//
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try {
//加载XML,获取对应的document Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; }catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }
doLoadBeanDefinitions 比较重要的是这句代码
int count = registerBeanDefinitions(doc, resource);
真正的执行在这里DefaultBeanDefinitionDocumentReader 类中的doRegisterBeanDefinitions方法,这个方法的代码如下
BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root);
//真正解析bean标签的地方 parseBeanDefinitions(root, this.delegate); postProcessXml(root); this.delegate = parent; } 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)) {
//系统默认的bean标签 parseDefaultElement(ele, delegate); } else {
//自定义的 bean 标签 delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
这时候我们看到这里才是真正解析xml文件里bean标签的内容。