zoukankan      html  css  js  c++  java
  • Spring-IOC源码解读2.1-BeanDefinition的Resource定位

    Spring通过ResourceLoader来处理得到的Resource。在前面我们知道容器初始化是以refresh()方法为入口的,内部的实现首先准备上下文,然后通过obtainFreshBeanFactory()方法获取beanFactory,

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();
            if (logger.isDebugEnabled()) {
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
            }
            return beanFactory;
        }

    进入AbstractRefreshableApplicationContext类的refreshBeanFactory()方法:

    protected final void refreshBeanFactory() throws BeansException {
            //如果已经存在beanfactory则先销毁之后再重新创建
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                //通过createBeanFactory()方法创建一个Ioc容器供容器使用,可以看到这个容器的类型是DefaultListableBeanFactory 
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                // 启动loadBeanDifinitions来载入BeanDifinition,因为有多种载入方式,这里通过一个抽象函数把具体的实现委托给子类来完成
                loadBeanDefinitions(beanFactory);
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }

    BeanDefinition的具体载入过程委托给了AbstractRefreshableApplicationContext的子类完成,我们测试代码中实现该逻辑的子类就是AbstractXMLApplicationContext类,进入loadBeanDefinitions()方法:

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // 为指定的BeanFactory创建一个XmlBeanDefinitionReader 
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // 使用此上下文的资源加载环境配置BeanDefinitionReader,由于AbstartactXmlApplication继承了DefaultResourceLoader,所以这里的ResourceLoader传的是this
            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);
        }
    

    上面的loadBeanDefinitions方法中设置了ResourceLoader对象用来定位Resource,由于AbstartactXmlApplicationContext继承自DefaultResourceLoader,所以该类本身就是一个加载器。Spring设计的时候解耦的非常好,实际上BeanDefinition的定位,读入,注册过程是分开进行的。我们看下DefaultResourceLoader是如何实现资源定位的,

    public Resource getResource(String location) {
    		Assert.notNull(location, "Location must not be null");
    		if (location.startsWith(CLASSPATH_URL_PREFIX)) {
    			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
    		}
    		else {
    			try {
    				// Try to parse the location as a URL...
    				URL url = new URL(location);
    				return new UrlResource(url);
    			}
    			catch (MalformedURLException ex) {
    				// No URL -> resolve as resource path.
    				return getResourceByPath(location);
    			}
    		}
    	}
    

    上面的getResourceByPath()方法会根据路径加载Resource对象

    protected Resource getResourceByPath(String path) {
    		return new ClassPathContextResource(path, getClassLoader());
    	}
    

    上面方法返回的是一个ClassPathContextResource对象,通过这个对象Spring就可以进行相关的I/O操作了。到这里我们就已经完成BeanDefinition的定位了。在BeanDefinition定位完成的基础上我们就可以通过返回的Resource对象进行BeanDefinition的载入了。

  • 相关阅读:
    java内部类案例
    java内部类之成员内部类之局部内部类
    java内部类之成员内部类之匿名内部类
    java静态内部类
    java内部类之成员内部类实例
    java内部类之成员内部类
    UDP和TCP的区别和联系
    SSM
    连接各种数据库
    JDBC数据库连接
  • 原文地址:https://www.cnblogs.com/pepper7/p/7670913.html
Copyright © 2011-2022 走看看