亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

spring如何獲取bean的源碼解析

發布時間:2021-04-26 15:02:38 來源:億速云 閱讀:122 作者:小新 欄目:開發技術

這篇文章主要介紹了spring如何獲取bean的源碼解析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

源碼

直接看源碼吧

@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
 
	@Override
	public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}
 
	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		return doGetBean(name, null, args, false);
	}
 
 
	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
			throws BeansException {
 
		return doGetBean(name, requiredType, args, false);
	}
 
 
	@SuppressWarnings("unchecked")
	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        
        // 把name轉化成beanName,也就是把FactoryBean的名稱轉化成beanName如果有別名則用別名
		final String beanName = transformedBeanName(name);
		Object bean;
 
		// 從緩存中獲取實例
        // 可能是需要的Bean實例,也可能是FactoryBean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
            // 獲取需要的bean或者FactoryBean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
 
		else {
			// 判斷prototype類型的bean是否存在循環引用
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
 
			// 校驗父類BeanFactory
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// 父類去獲取bean
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
            
            // 標記成已創建
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}
 
			try {
                // 把原來BeanDefinition轉換成RootBeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
 
				// 獲取依賴的bean,也就是通過@DependsOn注入進來的bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
                        // 校驗dependsOn的bean是否存在循環應用
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
                        // 加入到引用的緩存中,由于校驗dependsOn循環引用
						registerDependentBean(dep, beanName);
                        // 獲取@dependsOn的bean
						getBean(dep);
					}
				}
 
				// 創建單例的bean
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
                    // 獲取需要的bean或者FactoryBean
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
                // 創建prototype的bean
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}
                // 創建其他的bean,比如session,request等
				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
 
		// 如果要求的類型不是這個bean的實例類型,則進行轉換
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

獲取bean的整體流程就像上面源碼所示,這里再梳理下spring獲取bean的整個流程

1.先轉換bean的名稱,轉換成beanName。這里意思就是,我們在獲取bean的時候,可能是FactoryBean的名稱(&開頭),這里轉成不帶&開頭的名稱,如果有別名,再獲取別名。

2.從緩存中獲取bean,這里的緩存分為一二三級緩存,也就是我們常常被問到了spring三級緩存,具體邏輯下面再說。

3.根據獲取的到對象再去獲取我們想要的bean,因為這里獲取到的對象可能是我們需要的bean,也可能是FactoryBean。

4.如果緩存中沒有,那么我們就要自己去創建bean了。

5.查看有沒有父類的BeanFactory,如果有,那么就父類去創建bean。

6.獲取要創建的bean對象的@DependsOn注解上的名稱,先去創建DependsOn的bean,并且校驗是否存在循環引用

7.創建bean,根據類型創建不同的bean,比如singleton,prototype,request,session等。

8.如果需要轉換類型,則進行類型轉換。

整體的獲取bean的流程就是這樣了,其中有些具體流程接著分析。

從緩存中獲取bean對象

public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
 
 
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 從一級緩存中獲取
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
                // 從二級緩存中獲取
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                    // 從三級緩存中獲取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

spring通過三級緩存來解決循環依賴的問題。簡單來介紹下三級緩存。

1. singletonObjects為一級緩存,我們實例化的bean都在這個map里,俠義的說singletonObjects才是我們真正的spring容器,存放bean的地方。

2. earlySingletonObjects為二級緩存,是存放未完成的bean的緩存,如果有代理的話,存放的是代理對象。

3. singletonFactories為三級緩存,存放的是一個ObjectFactory,數據通過getObject方法獲得。

從BeanInstance中獲取對象

接下來看getObjectForBeanInstance方法。

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
 
        // name是不是factoryBean的name(&開頭的)
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
            // 如果是FactoryBeanName,但是獲取到的bean不是FactoryBean,則拋異常
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
			}
		}
 
        // 如果bean不是FactoryBean,或者名稱是FactoryBeanName,直接返回BeanInstace
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}
 
		Object object = null;
		if (mbd == null) {
            // 從緩存中獲取
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// 這里可以確定beanInstance是FactoryBean了
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
            // 通過FactoryFBean中獲取需要的beanInstance
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

這里是通過BeanInstance獲取我們想要的bean,這里也簡單說下流程

1. 首先判斷name是不是FactoryBean的name,也就是&開頭的name,如果是去判斷beanInstance是不是FactoryBean,如果beanInstance不是FactoryBean則拋異常。

2. 由于上面已經判斷過,如果name是FactoryBeanName,但是BeanInstance不是FactoryBean的話,就會拋出異常。所以如果BeanInstance如果不是FactoryBean的話,那么name一定不是FactoryBeanName。那么就直接返回BeanInstance就是我們需要的了。

如果name是FactoryBeanName,那么我們需要獲取的就是FactoryBean,也直接返回就可以了。

3. 如果都沒有返回,那么已經可以確定我們此時的已經可以確定BeanInstance是FactoryBean了,因為如果不是FactoryBean的話,在!(beanInstance instanceof FactoryBean)就已經返回了。

4. 通過FactoryBean的getObject方法獲取我們需要的bean實例。

創建bean

根據@dependsOn查找依賴的bean并且加到依賴里面去沒有什么好說的,代碼邏輯也很簡單,接下來看創建單例bean。其他類型的bean的創建也都差別不大。看源碼

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
            // 直接從一級緩存中取
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
                // 在沒創建bean之前的處理
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
                    // 獲取創建的bean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
                    // 創建結束之后的工作
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
                    // 加到一級緩存中,其實也就是真正的容器中了
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

對于創建單例bean的主要流程就是如此,傳入一個beanName,和一個ObjectFactory。ObjectFactory中具體實現了創建bean的邏輯。在看具體創建bean的邏輯之前,我們還需要去看下getSingleton中的創建bean之前的工作和創建bean之后的工作。這里面就是查找bean的循環依賴的方法(和dependsOn不同)。主要是查找根據filed,set,構造器方法的循環依賴。

protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
 
	protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

可以看到代碼非常的簡單,就是創建bean之前,如果沒有排除依賴檢查,那么就加入到正在創建的Set中,如果加入不進去,說明之前已經加過,這就產生了循環依賴,從而拋出異常。

如果在創建bean之后,沒有排除檢查依賴,并且移除失敗,說明已經不在Set中,也會拋出異常。

好了,既然明白了spring是如何校驗循環依賴的,也看到了三級緩存,后面再說為什么不能解決構造器依賴就很好說了。接著看創建bean的方法。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
 
		if (logger.isDebugEnabled()) {
			logger.debug("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;
        
        // 獲取要創建bean的class
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            // 如果沒有beanclass,設置beanclass
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}
 
		// 配置方法重載
		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}
 
		try {
			// 那些beanPostProcessor如果能產生代理,則直接返回bean
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}
 
		try {
            // 創建bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isDebugEnabled()) {
				logger.debug("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException ex) {
			// A previously detected exception with proper bean creation context already...
			throw ex;
		}
		catch (ImplicitlyAppearedSingletonException ex) {
			// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

這里其實還是沒有到創建bean的過程,還是在創建bean的一些準備工作。其實我們可以發現,spring中,真正做事的都是do開頭的方法。

這邊的流程就是設置beanClass,后面需要根據反射來創建bean。然后會根據spring里面的beanPostProcessor,看看有沒有能產生代理bean的,如果有就返回,沒有就去創建bean。

看真正的doCreateBean方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
 
		// 裝飾Bean的對象
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
            // 通過緩存獲取
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 創建bean
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
 
		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                    // 調用MergedBeanDefinitionPostProcessor的方法
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}
 
		// 加入到三級緩存中去
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
 
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            // 填充依賴的bean,field注入,和方法注入的bean
			populateBean(beanName, mbd, instanceWrapper);
            // 調用初始化的方法
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
 
		if (earlySingletonExposure) {
            // 獲取二級緩存的值
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
                // 如果一致,則直接使用二級緩存的對象
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
                // 如果調用初始化后的bean和之前的bean不一致,并且有依賴
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    // 查找循環依賴
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
                        // 如果有循環依賴并且在創建中,則拋出異常
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}
 
		// 注冊disposableBean
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}
 
		return exposedObject;
	}

真正創建bean這里還是有點復雜的。這里再進行一個簡單梳理。

1. 根據class還有bean以及參數創建bean。

2. 調用beanPostprocessor的方法,調用屬于MergedBeanDefinitionPostProcessor的方法。對bean進行一些處理,比如找到那些依賴的bean的field和method。

3. 將bean加入到三級緩存中去。

4. 填充bean需要注入的其他bean。

5. 調用初始化方法,先去調用@PostConstruct注解方法,然后調用InitializingBean的afterPropertiesSet,以及自定義的init-method方法。在bean調用初始化方法之后,再去調用后置接口看看是否需要生成Aop代理。

6. 接著進行校驗。這里稍微比較復雜一點。如果從二級緩存能取到,那就說明之前被別人從三級緩存拿出來過了。可能是因為循環依賴,也可能是因為別的地方調用了getBean方法了。從三級緩存拿出來的時候有個getEarlyBeanReference的方法,就是查看是否要生成代理的bean。如果生成過了,那么在調用第五步的時候,就不會在生成代理了。這樣exposedObject ==bean,直接只用代理返回。

如果不相等:這里的情況就是如果是spring自己的@Async,在從二級緩存生成代理之后,再去調用第五步時候一樣會生成代理。所以exposedObject !=bean,所以在再往下發現有循環調用,并且bean還在創建時,就會拋出異常了。所以一般慎用spring的@Async。但是一般也可以使用@Lazy進行處理。至于原理后面再說。

到這里spring的創建bean就結束了。然后返回時候就到了入口方法getBean的getObjectForBeanInstance的方法,到底需要的bean還是FactoryBean。

最后就是如果requiredType和實例不一樣就要進行類型轉換了。

感謝你能夠認真閱讀完這篇文章,希望小編分享的“spring如何獲取bean的源碼解析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

梅河口市| 敦化市| 化州市| 宁海县| 隆回县| 天柱县| 察雅县| 信阳市| 大港区| 嵊州市| 方山县| 措勤县| 汉川市| 安国市| 舒城县| 衡阳市| 巴马| 虹口区| 株洲市| 甘洛县| 荔波县| 香格里拉县| 西宁市| 岫岩| 英吉沙县| 南宫市| 安达市| 游戏| 屏东市| 侯马市| 娄烦县| 阿图什市| 泸西县| 陆川县| 兰溪市| 宽甸| 简阳市| 岳西县| 墨江| 贵溪市| 芦山县|