博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BeanDefinition的定位
阅读量:4619 次
发布时间:2019-06-09

本文共 10164 字,大约阅读时间需要 33 分钟。

概念

BeanDefinition的存在形式有很多种,例如文件系统中的Bean定义文件或类路径中的Bean定义文件。这就意味需要不同的寻址方式在找到这些Bean定义文件。Resource定位指的是BeanDefinition的资源定位,就是找到这些Bean定义文件,并将这些信息抽象为统一的Resource对象,方便后面载入。

分析定位过程

以编程的方式使用DefaultListableBeanFactory时,我们会手动定义一个Resource来定位容器使用BeanDefinition:ClassPathResource res = new ``ClassPathResource("bean.xml");然后定义一个特定的读取器来读取这个资源,因为DefaultListableBeanFactory是一个纯粹的IoC容器,并没有自带帮我们定位资源和读取资源的功能,所以需要手动为其配置特定的读取器。所以这里就能看出使用ApplicationContext的优势所在,因为在ApplicationCo-ntext中,已经为我们提供了一系列加载不同Resource的读取器的实现,例如FileSystemXmlApplicationContext,ClassPathXmlApplicationContext以及XmlWebApplicationContext等,简单地从这些类的名字上分析,可以清楚地看到它们可以提供哪些不同的Resource读入功能。当然,使用DefaultListable-BeanFactory这种更底层的容器,能提高定制IoC容器的灵活性。下面分析FileSystemXmlApplicationContext的资源定位过程。

在上面的分析中,我们可以了解到FileSystemXmlApplicationContext的基本功能都在其基类中完成,它只是在构造函数中调用基类的refresh()来实例化容器和定义getResourceByPath()来定位BeanDefinition资源。所以可以知到getResourceByPath()是该容器定位资源调用的最后的方法,查看该方法的调用栈,便可了解整个定位过程。

image.png

分析调用栈:

  • FileSystemXmlApplicationContext构造器中的refresh()方法是开始容器初始化的入口方法,由refresh()来启动整个调用。
  • 在FileSystemXmlApplicationContext的基类AbstractRefreshableApplicationContext中的refreshBeanFactory()进行容器的初始化。从这里可知实际使用的BeanFactory是DefaultListableBeanFactory。代码如下:
/**     * This implementation performs an actual refresh of this context's underlying     * bean factory, shutting down the previous bean factory (if any) and     * initializing a fresh bean factory for the next phase of the context's lifecycle.     */    @Override    protected final void refreshBeanFactory() throws BeansException {    //这里判断如果已经建立了BeanFactory,则销毁并关闭该BeanFactory        if (hasBeanFactory()) {            destroyBeans();            closeBeanFactory();        }    /**      *创建实际存储BeanDefinition的DefaultListableBeanFactory,      *并调用loadBeanDefinitions(beanFactory)载入BeanDefinition信息      */         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);        }    }  protected DefaultListableBeanFactory createBeanFactory() {        return new DefaultListableBeanFactory(getInternalParentBeanFactory());    }
  • loadBeanDefinitions(DefaultListableBeanFactory beanFactory),这个方法在基类AbstractRefreshableApp-licationContext中定义为抽象函数,因为允许有不同的载入方式,这里通过一个抽象函数把具体实现委托给子类,见图一和图二。FileSystemXmlApplicationContext是用xml方式读取的,所以基类AbstractXmlApplication-Context实现了这个方法。在这个方法中将DefaultListableBeanFactory绑定给BeanDefinitionReader,用于后续定位、载入和注册的回调。还需要注意的是beanDefinitionReader.setResourceLoader(this)这个方法,ResourceLoader的主要功能是用来定位和获取Resource对象的,而在Spring中每个ApplicationContext都是DefaultResourceLoader的子类(见图四),所以FileSystemXmlApplicationContext中的getResourceByPath(S-tring path)是重写父类的方法。BeanDefinitionReader绑定完需要后续回调的组件后,就由BeanDefinitionR-eader继续后续处理,见图三。

     java /** * Load bean definitions into the given bean factory, typically through * delegating to one or more bean definition readers. * @param beanFactory the bean factory to load bean definitions into * @throws BeansException if parsing of the bean definitions failed * @throws IOException if loading of bean definition files failed * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader */ //AbstractRefreshableApplicationContext中的抽象方法。 protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException;
    image.png

    /**   * Loads the bean definitions via an XmlBeanDefinitionReader.   * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader   * @see #initBeanDefinitionReader   * @see #loadBeanDefinitions   */  @Override  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {      // Create a new XmlBeanDefinitionReader for the given BeanFactory.      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);      // Configure the bean definition reader with this context's      // resource loading environment.      beanDefinitionReader.setEnvironment(this.getEnvironment());      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);  }

    image.png

  • loadBeanDefinitions(XmlBeanDefinitionReader reader)方法:对配置文件路径进行判断,如果路径不为空,则根据路径进行定位。
/**     * Load the bean definitions with the given XmlBeanDefinitionReader.     * 

The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory} * method; hence this method is just supposed to load and/or register bean definitions. * @param reader the XmlBeanDefinitionReader to use * @throws BeansException in case of bean registration errors * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */ protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); //对configResources进行载入解析和注册 if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); //根据configLocations定位Resource if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }

  • loadBeanDefinitions(String location, Set actualResources)方法:根据路径定位。
/**     * Load bean definitions from the specified resource location.     * 

The location can also be a location pattern, provided that the * ResourceLoader of this bean definition reader is a ResourcePatternResolver. * @param location the resource location, to be loaded with the ResourceLoader * (or ResourcePatternResolver) of this bean definition reader * @param actualResources a Set to be filled with the actual Resource objects * that have been resolved during the loading process. May be null * to indicate that the caller is not interested in those Resource objects. * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors * @see #getResourceLoader() * @see #loadBeanDefinitions(org.springframework.core.io.Resource) * @see #loadBeanDefinitions(org.springframework.core.io.Resource[]) */ public int loadBeanDefinitions(String location, Set

actualResources) throws BeanDefinitionStoreException { //这里取得ResourceLoader,就是之前绑定的FileSystemXmlApplicationContext ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } //这里对Resource的路径模式进行解析。 if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { //调用DefaultResourceLoader的getResource完成具体的Resource定位 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. //调用DefaultResourceLoader的getResource完成具体的Resource定位 Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }

  • getResource(String location)方法:DefaultResourceLoader具体的Resource定位方法。
public Resource getResource(String location) {        Assert.notNull(location, "Location must not be null");  //这里处理带有classpath标识的Resource        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标识的Resource定位                URL url = new URL(location);                return new UrlResource(url);            }            catch (MalformedURLException ex) {                // No URL -> resolve as resource path.        //如果既不是classpath.也不是URL标识的Resource定位,则把getResource的        //重任交给getResourceByPath,这个方法是一个protected方法.默认的实现是得到        //一个ClassPathContextResource,这个方法常常会用子类来实现                return getResourceByPath(location);            }        }    }    //getResourceByPath的默认实现  protected Resource getResourceByPath(String path) {        return new ClassPathContextResource(path, getClassLoader());    }
  • 上述代码的getResourceByPath(location);在这里就调用子类FileSystemXmlApplicationContext的该方法。

转载于:https://www.cnblogs.com/huangzefeng/p/10322405.html

你可能感兴趣的文章
traefik添加多证书
查看>>
PhantomJs 笔记
查看>>
js设计模式--语言类型
查看>>
C#多线程之二:ManualResetEvent和AutoResetEvent
查看>>
Java如何获取系统cpu、内存、硬盘信息
查看>>
忽略UserInterfaceState.xcuserstate
查看>>
ReactNative--Flexbox布局
查看>>
java实现读取文件大全
查看>>
[Cordova] 无法显示Alert视窗
查看>>
借助过度区选择阈值
查看>>
价格正则
查看>>
对for 循环的初认识
查看>>
评论列表显示及排序,个人中心显示
查看>>
JavaWeb学习笔记总结 目录篇
查看>>
C#根据html生成PDF
查看>>
Neutron SDN 手动实现手册
查看>>
linux下core文件调试方法
查看>>
20个创意404错误页面设计的启示
查看>>
DBCP连接池配置参数说明
查看>>
C语言实现四舍五入
查看>>