Spring的XML解析原理,这一次全搞懂再走( 三 )

在这个方法中首先会清除掉上一次创建的BeanFactory和对象实例 , 然后创建了一个DefaultListableBeanFactory对象并传入到了loadBeanDefinitions方法中 , 这也是一个模板方法 , 因为我们的配置不止有xml , 还有注解等 , 所以这里我们应该进入AbstractXmlApplicationContext类中:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {//创建xml的解析器 , 这里是一个委托模式XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());//这里传一个this进去 , 因为ApplicationContext是实现了ResourceLoader接口的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);//主要看这个方法loadBeanDefinitions(beanDefinitionReader); }首先创建了一个XmlBeanDefinitionReader对象 , 见名知意 , 这个就是解析xml的类 , 需要注意的是该类的构造方法接收的是BeanDefinitionRegistry对象 , 而这里将DefaultListableBeanFactory对象传入了进去(别忘记了这个对象是实现了BeanDefinitionRegistry类的) , 如果你足够敏感 , 应该可以想到后面会委托给该类去注册 。 注册什么呢?自然是注册BeanDefintion 。 记住这个猜想 , 我们稍后来验证是不是这么回事 。 接着进入loadBeanDefinitions方法获取之前保存的xml配置文件路径 , 并委托给XmlBeanDefinitionReader对象解析加载:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}//获取需要加载的xml配置文件String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);} }最后会进入到抽象父类AbstractBeanDefinitionReader中:
public int loadBeanDefinitions(String location, @Nullable Set actualResources) throws BeanDefinitionStoreException {// 这里获取到的依然是DefaultListableBeanFactory对象ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {//把字符串类型的xml文件路径 , 形如:classpath*:user/**/*-context.xml,转换成Resource对象类型 , 其实就是用流//的方式加载配置文件 , 然后封装成Resource对象Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);//主要看这个方法int count = loadBeanDefinitions(resources);if (actualResources != null) {Collections.addAll(actualResources, resources);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");}return count;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// Can only load single resources by absolute URL.Resource resource = resourceLoader.getResource(location);int count = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");}return count;} }