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

这个方法是一个典型的模板方法模式的实现 , 第一步是准备初始化容器环境 , 这一步不重要 , 重点是第二步 , 创建BeanFactory对象、加载解析xml并封装成BeanDefinition对象都是在这一步完成的 。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();return getBeanFactory(); }点进去看是调用了refreshBeanFactory方法 , 但这里有两个实现 , 应该进哪一个类里面呢?
Spring的XML解析原理,这一次全搞懂再走文章插图
如果你还记得前面的继承体系 , 那你就会毫不犹豫的进入AbstractRefreshableApplicationContext类中 , 所以在阅读源码的过程中一定要记住类的继承体系 。
protected final void refreshBeanFactory() throws BeansException {//如果BeanFactory不为空 , 则清除BeanFactory和里面的实例if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {//创建DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());//设置是否可以循环依赖 allowCircularReferences//是否允许使用相同名称重新注册不同的bean实现.customizeBeanFactory(beanFactory);//解析xml , 并把xml中的标签封装成BeanDefinition对象loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);} }在这个方法中首先会清除掉上一次创建的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;} }