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

1,231 阅读11分钟

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

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

BeanFactory 简介

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

ResourceLoader简介

ResourceLoader并不能将其看成是Spring独有的功能,spring Ioc只是借助于ResourceLoader来实现资源加载。也提供了各种各样的资源加载方式:

  • DefaultResourceLoader 首先检查资源路径是否以classpath:前缀打头,如果是,则尝试构造ClassPathResource类 型资源并返回。否则, 尝试通过URL,根据资源路径来定位资源

  • FileSystemResourceLoader 它继承自Default-ResourceLoader,但覆写了getResourceByPath(String)方法,使之从文件系统加载资源并以 FileSystemResource类型返回

    • ResourcePatternResolver 批量查找的ResourceLoader

spring与ResourceLoader之间的关系

所有ApplicationContext的具体实现类都会直接或者间接地实现AbstractApplicationContext,AbstactApplicationContext 依赖了了DeffaultResourceLoader, ApplicationContext 继承了ResourcePatternResolver,所到头来ApplicationContext的具体实现类都会具有DefaultResourceLoader 和 PathMatchingResourcePatterResolver的功能。这也就是会什么ApplicationContext可以实现统一资源定位。

接下来进入正题: 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定义覆盖、是否允许bean之间的循环引用
      //bean定义覆盖的属性默认是true,重复了会直接覆盖
      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.向注册中心注册beanDefinition的过程(将beanDefinition放入缓存)。

resource定位

AbstractXmlApplicationContext#loadBeanDefinitions(beanFactory) 加载 Bean:

// AbstractXmlApplicationContext.java L80

@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

// XmlBeanDefinitionReader.java L314

    /**
	 * Load bean definitions from the specified XML file.
	 * 从xml里加载bean实例
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		...
		//从threadlocal中获取资源set
		Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		//将resource放入setif (!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());
				}
				//此处调用388行的doLoadBeanDefinitions()
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally {
				inputStream.close();
			}
		} 
		//此处省略处理异常、清楚链表和threadload相关代码
		...
	}

接下来继续看//XmlBeanDefinitionReader.java L388的实现

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {
		try {
		    //校验xml文件的是xsd 还是 dtd格式的,然后调用 DefaultDocumentLoader#doLoadDocument将流解析成document对象
			Document doc = doLoadDocument(inputSource, resource);
			//将document和资源封装成bean实例
			return registerBeanDefinitions(doc, resource);
		}
		//省略若干异常处理
		...
	}

// XmlBeanDefinitionReader.java L505

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //构建DefaultBeanDefinitionDocumentReader的实例由documentReader负责解析xml并封装到beandefinition里
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//BeanDefinitionRegistry 负责将bean实例注册到bean工厂
		int countBefore = getRegistry().getBeanDefinitionCount();
		//下面会详细展开说明
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
    

经过艰难险阻,磕磕绊绊,我们终于到了核心逻辑的底部doRegisterBeanD巳finitions(root) , 至少我们在这个方法中看到了希望。 如果说以前一直是XML 加载解析的准备阶段,那么doRegisterBeanDefinitions 算是真正地 开始进行解析了,我们期待的核心部分真正开始了:

==DefaultBeanDefinitionDocumentReader==

//DefaultBeanDefinitionDocumentReader.java L116

protected void doRegisterBeanDefinitions(Element root) {
	
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

        //处理profile
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}
        //模板方法模式,让子类去实现,利于用户自己拓展
		preProcessXml(root);
		
		parseBeanDefinitions(root, this.delegate);
		
        //模板方法模式,让子类去实现,利于用户自己拓展
		postProcessXml(root);

		this.delegate = parent;
	}

继续跟踪parseBeanDefinitions(root, this.delegate); //DefaultBeanDefinitionDocumentReader.java L157

    /**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	    //判断当前元素是否是beans节点
		if (delegate.isDefaultNamespace(root)) {
		    //beans
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
			    //循环beans下面的节点
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
					    //自定义节点
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
		    //自定义的元素
			delegate.parseCustomElement(root);
		}
	}

从上面的代码,我们可以看到,对于每个配置来说,分别进入到 parseDefaultElement(ele, delegate); 和 delegate.parseCustomElement(ele); 这两个分支了。

parseDefaultElement(ele, delegate) 代表解析的节点是 、、、 这几个。 这里的四个标签之所以是 default 的,是因为它们是处于这个 namespace 下定义的:www.springframework.org/schema/bean…

而对于其他的标签,将进入到 delegate.parseCustomElement(element) 这个分支。如我们经常会使用到的 、、、等。

回过神来,看看处理 default 标签的方法:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
		    //import
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
		    //alias
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		    //bean  创建bean的入口
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// beans
			doRegisterBeanDefinitions(ele);
		}
	}

这里我们不会对每一个标签进行解析,仅仅对最重要的进行跟踪 解析的入口: //DefaultBeanDefinitionDocumentReader.java L294

    /**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	    // 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中,细节往下看
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
		    //对自定义属性进行解析。忽略
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 注册bean
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// bean注册完成后发送事件,但是这里是空实现,留给用户扩展
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

将xml信息载入到beanDefinition中。

==BeanDefinitionParserDelegate==

// BeanDefinitionParserDelegate L437

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		//将 name 属性的定义按照 ”逗号、分号、空格“切分,形成一个别名列表数组,
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		//// 如果没有指定id, 那么用别名列表的第一个名字作为beanName
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
		}
        
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
        // 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中,
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		// 到这里,整个 <bean /> 标签就算解析结束了,一个 BeanDefinition 就形成了。
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
			 // 如果都没有设置 id 和 name,那么此时的 beanName 就会为 null,进入下面这块代码产生生成相应的别名,可以忽略
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			// 返回 BeanDefinitionHolder
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

==// BeanDefinitionParserDelegate.java#parseBeanDefinitionElement L522==

    /**
	 * Parse the bean definition itself, without regard to name or aliases. May return
	 * {@code null} if problems occurred during the parsing of the bean definition.
	 */
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

        //parseState里维护了一个栈,保证先进后出
		this.parseState.push(new BeanEntry(beanName));

		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		    //取出class属性
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			    //取出parent属性
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
			//用class 和parent创建一个GenericBeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
             // 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

             /**
               * 下面的一堆是解析 <bean>......</bean> 内部的子元素,
               * 解析出来以后的信息都放到 bd 的属性中
               */
         
            // 解析 <meta />
			parseMetaElements(ele, bd);
			// 解析 <lookup-method />
			parseLookupOverrideSubElements(ele,bd.getMethodOverrides());
			
			// 解析 <replaced-method />
			parseReplacedMethodSubElements(ele,bd.getMethodOverrides());

            // 解析 <constructor-arg />
			parseConstructorArgElements(ele, bd);
			// 解析 <property />
			parsePropertyElements(ele, bd);
			// 解析 <qualifier />
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

到这里,我们已经完成了根据 配置创建了一个 BeanDefinitionHolder 实例。 我们回到解析的入口: //DefaultBeanDefinitionDocumentReader.java L294

    /**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	    // 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中,细节往下看
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
		    //对自定义属性进行解析。忽略
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 注册bean
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// bean注册完成后发送事件,但是这里是空实现,留给用户扩展
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

接下来是注册bean实例的过程——

注册bean到缓存中

//BeanDefinitionReaderUtils#registerBeanDefinition L143

    /**
	 * Register the given bean definition with the given bean factory.
	 */
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		String beanName = definitionHolder.getBeanName();
		//调用BeanDefinitionRegistry实现类注册以beanName为key,bean实例作为value存入缓存中
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// 如果还有别名的话,也要根据别名统统注册一遍,不然根据别名就找不到 Bean 了
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
    			// alias -> beanName 保存它们的别名信息,这个很简单,用一个 map 保存一下就可以了,
                // 获取的时候,会先将 alias 转换为 beanName,然后再查找
				registry.registerAlias(beanName, alias);
			}
		}
	}

这里BeanDefinitionRegistry的实现类用DefaultListableBeanFactory 方法比较长,为了便于阅读,我将一些异常处理等非核心方法省略 //DefaultListableBeanFactory#registerBeanDefinition L793

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
        ...

		BeanDefinition oldBeanDefinition;
        // 从beanDefinitionMap缓存中取,之后会看到,所有的 Bean 注册后会放入这个 beanDefinitionMap 中
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
		    //allowBeanDefinitionOverriding  customizeBeanFactory(beanFactory) 里可以设置这个属性,默认是trueif (!isAllowBeanDefinitionOverriding()) {
			//不允许覆盖,抛异常
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			...打印相关日志
			//将beanName作为key,beanDefinition作为value放入map中,覆盖旧值
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
		    //该beanName未被创建
		    //判断alreadyCreated链表是否为空===判断是否已经有其他的 Bean 开始初始化
		    // 注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化,我们后面会有大篇幅说初始化过程,
            // 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				//为了集合迭代的稳定性,不能直接操作元集合(不能增加和删除元素个数)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					//新建一个临时集合来实现新增的beanname
					//beanDefinitionNames  预注册的bean实例的beanName集合
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					//manualSingletonNames  手动注册单例的beanName集合
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// 这是正常的开始
                // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
				this.beanDefinitionMap.put(beanName, beanDefinition);
				
				// 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
				this.beanDefinitionNames.add(beanName);
				
				// 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
                // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
                // 手动指的是通过调用以下方法注册的 bean :registerSingleton(String beanName, Object singletonObject)
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

总结一下,到这里已经初始化了 Bean 容器, 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到了注册中心