spring源码学习bean载入时的安全检测方式-threadlocal

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lxy344x/article/details/79072657

   SpringIOC容器启动后开启了BeanDefinition的Resource定位,载入和注册的三个过程,loadBeanDefinitions方法中提供了Resource的定位的三种方式,classpath,url,getResourceByPath,其次就是载入的过程,主要采用原始的IO的InputSource,但是在解析xml之前做了一些安全性的操作,这种安全性的操作可以用在自己的编码中。这个过程以XmlBeaDefinitionReader为例,方法loadBeanDefinitions中

/**
	 * Load bean definitions from the specified XML file.
	 * @param encodedResource the resource descriptor for the XML file,
	 * allowing to specify an encoding to use for parsing the file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		Assert.notNull(encodedResource, "EncodedResource must not be null");
		if (logger.isInfoEnabled()) {
			logger.info("Loading XML bean definitions from " + encodedResource.getResource());
		}
//通过上文中
//private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
  //          new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently //being loaded");
//可以知道resourcesCurrentlyBeingLoaded是一个threadlocal本地变量。
      Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) {
                        //如果从threadlocal中获取的currentResource为空则初始化一个容量为4的hashSet,并将                 //currentResource放入threadlocal中。
                        currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
                 //如果已经存在则抛出异常,提示发现有循环载入encodeResource,而终止载入。可以看出这里的、、//threadlocal只是一个防止循环第三个变量
                 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 {
                        //处理结束后将encodedResouce删除
                        currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) {
                            //从threadlocal中移除hashSet
                            this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
    ThreadLocal是如何保证线上安全的?ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。这里的不安全的变量即为encodedResource。threadlocal这种通过“以空间换时间”的方式比使用synchronized这种“以时间换空间”的同步机制更为简洁易懂。
展开阅读全文

没有更多推荐了,返回首页