转载

【spring 源码】IOC 之bean实例的创建

在对refreshBeanFactory()详细解析之前,先来看看spring的applicationContext的继承树:

【spring 源码】IOC 之bean实例的创建

这里有两个重要的接口,一个是BeanFactory,顾名思义是bean的工厂、容器,bean创建好了就回放入这个容器里,我们要用的bean实例都是从bean工厂提供的。另一个接口是ResourceLoader,它的实现类实现了读取配置文件,将配置封装成bean实例,然后将bean放入bean工厂。

BeanFactory 简介

【spring 源码】IOC 之bean实例的创建

ApplicationContext 继承了 ListableBeanFactory,这个 Listable 的意思就是,通过这个接口,我们可以获取多个 Bean,最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。 ApplicationContext 继承了 HierarchicalBeanFactory,Hierarchical 单词本身已经能说明问题了,也就是说我们可以在应用中起多个 BeanFactory,然后可以将各个 BeanFactory 设置为父子关系。 AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配 Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承,不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法 getAutowireCapableBeanFactory() 就知道了。 ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层所有的三个接口,而 ApplicationContext 没有。这点之后会用到。

ResourceLoader简介

接下来进入正题:

refreshBeanFactory() 刷新beanfactory

// AbstractRefreshableApplicationContext.java - 120

@Override
protected final void refreshBeanFactory() throws BeansException {
   // 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
   // 注意,应用中 BeanFactory本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext 是否有 BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      // 初始化一个 DefaultListableBeanFactory,为什么用这个,我们马上说。
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 用于 BeanFactory 的序列化
      beanFactory.setSerializationId(getId());
      // 下面这两个方法很重要,
      // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
      customizeBeanFactory(beanFactory);
      // 加载 Bean 到 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);
   }
}
复制代码

整个过程主要分为了三个步骤:

1.resource定位

 2.beanDefinition的载入。

 3.向ioc容器注册beanDefinition的过程。
复制代码

loadBeanDefinitions(beanFactory) 加载 Bean:

// AbstractXmlApplicationContext.java 80

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // 给这个 BeanFactory 实例化一个 XmlBeanDefinitionReader
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
 
   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
 
   // 初始化 BeanDefinitionReader,其实这个是提供给子类覆写的,
   initBeanDefinitionReader(beanDefinitionReader);
   // 重点来了,继续往下
   loadBeanDefinitions(beanDefinitionReader);
}
复制代码

读取配置的操作在 XmlBeanDefinitionReader 中,其负责加载配置、解析。 // AbstractXmlApplicationContext.java 120

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    //如果调用的构造器是new ClassPathXmlApplicationContext(String path, Class<?> clazz),获取其路径下的资源
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      reader.loadBeanDefinitions(configResources);
   }
   //如果构造器调用的的是 new ClassPathXmlApplicationContext(String configLocation),获取其资源
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      reader.loadBeanDefinitions(configLocations);
   }
}
复制代码

这里两个分支都是在加载bean实例,过程类似,只分析reader.loadBeanDefinitions(configResources);

//AbstractBeanDefinitionReader.java L177

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
	Assert.notNull(resources, "Resource array must not be null");
	int counter = 0;
	for (Resource resource : resources) {
	    //这里用了典型的模板模式,实际调用的是XmlBeanDefinitionReader#loadBeanDefinitions
		counter += loadBeanDefinitions(resource);
	}
	return counter;
}
复制代码

//XmlBeanDefinitionReader.java L314

/**
	 * Load bean definitions from the specified XML file.
	 * 从xml里加载bean实例
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		...
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(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();
			}
		}
	}
复制代码
原文  https://juejin.im/post/5c9dead1f265da30941153cf
正文到此结束
Loading...