网站建设公司,做网站是怎么回事,网站评论回复如何做,网站建设几个文件夹文章目录写在前面关键类ConfigurationClassPostProcessor1、ConfigurationClassPostProcessor的注册2、ConfigurationClassPostProcessor的处理过程#xff08;1#xff09;parse方法中#xff0c;Bean方法的处理#xff08;2#xff09;注册解析Bean标注的方法写在前面
…
文章目录写在前面关键类ConfigurationClassPostProcessor1、ConfigurationClassPostProcessor的注册2、ConfigurationClassPostProcessor的处理过程1parse方法中Bean方法的处理2注册解析Bean标注的方法写在前面
日常开发中我们都会使用Bean定义一个Spring的Bean那么这简单的一个注解背后隐藏着多少的秘密
今天我们就一起把这个秘密拆解开。
关键类ConfigurationClassPostProcessor
该场景只适用于基于注解方式启动的容器。
1、ConfigurationClassPostProcessor的注册
先上一段代码
AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();// 注册 Configuration Class
context.register(LiveBeansViewDemo.class);// 启动 Spring 应用上下文
context.refresh();// 关闭 Spring 应用上下文
context.close();代码很简单其中Bean的处理关键类ConfigurationClassPostProcessor的处理就隐藏在new AnnotationConfigApplicationContext()这个代码里我们继续往下看
// org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext()
public AnnotationConfigApplicationContext() {this.reader new AnnotatedBeanDefinitionReader(this);this.scanner new ClassPathBeanDefinitionScanner(this);
}上面源码中会new一个AnnotatedBeanDefinitionReader而Springboot启动web项目也会new这样一个类它们的处理逻辑基本是相同的。
在AnnotatedBeanDefinitionReader构造器中会进行以下的处理
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {this(registry, getOrCreateEnvironment(registry));
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {Assert.notNull(registry, BeanDefinitionRegistry must not be null);Assert.notNull(environment, Environment must not be null);this.registry registry;this.conditionEvaluator new ConditionEvaluator(registry, environment, null);// 注册AnnotationConfigProcessorsAnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}在源码最后会调用工具类注册AnnotationConfigProcessors
// org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry)
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {registerAnnotationConfigProcessors(registry, null);
}public static SetBeanDefinitionHolder registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, Nullable Object source) {DefaultListableBeanFactory beanFactory unwrapDefaultListableBeanFactory(registry);if (beanFactory ! null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}SetBeanDefinitionHolder beanDefs new LinkedHashSet(8);// 注册ConfigurationClassPostProcessor到if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException(Cannot load optional framework class: PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;
}上面源码我们可以分析出来会依次注册ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor、EventListenerMethodProcessor、DefaultEventListenerFactory等很多BeanPostProcessor顾名思义就能知道大体是干什么的。
我们今天主要是研究ConfigurationClassPostProcessor。 到此为止ConfigurationClassPostProcessor已经注册到BeanFactory中作为一个BeanDefinition了。
2、ConfigurationClassPostProcessor的处理过程
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor就有了Bean的依赖查找和注入注册的能力实现postProcessBeanDefinitionRegistry方法可以在 IOC容器启动的BeanFactory 后置处理阶段-invokeBeanFactoryPostProcessors阶段进行调用更多请移步Spring应用上下文生命周期详解及源码分析Spring IOC容器启动及关闭过程超详细解释上。
我们来分析一下ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
// org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException(postProcessBeanDefinitionRegistry already called on this post-processor against registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException(postProcessBeanFactory already called on this post-processor against registry);}this.registriesPostProcessed.add(registryId);processConfigBeanDefinitions(registry);
}public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {ListBeanDefinitionHolder configCandidates new ArrayList();String[] candidateNames registry.getBeanDefinitionNames();for (String beanName : candidateNames) {BeanDefinition beanDef registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) ! null) {if (logger.isDebugEnabled()) {logger.debug(Bean definition has already been processed as a configuration class: beanDef);}}else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// Return immediately if no Configuration classes were foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined Order value, if applicableconfigCandidates.sort((bd1, bd2) - {int i1 ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// Detect any custom bean name generation strategy supplied through the enclosing application contextSingletonBeanRegistry sbr null;if (registry instanceof SingletonBeanRegistry) {sbr (SingletonBeanRegistry) registry;if (!this.localBeanNameGeneratorSet) {BeanNameGenerator generator (BeanNameGenerator) sbr.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);if (generator ! null) {this.componentScanBeanNameGenerator generator;this.importBeanNameGenerator generator;}}}if (this.environment null) {this.environment new StandardEnvironment();}// Parse each Configuration classConfigurationClassParser parser new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);SetBeanDefinitionHolder candidates new LinkedHashSet(configCandidates);SetConfigurationClass alreadyParsed new HashSet(configCandidates.size());do {// 关键方法见1parser.parse(candidates);parser.validate();SetConfigurationClass configClasses new LinkedHashSet(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// Read the model and create bean definitions based on its contentif (this.reader null) {this.reader new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 关键方法见2this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();if (registry.getBeanDefinitionCount() candidateNames.length) {String[] newCandidateNames registry.getBeanDefinitionNames();SetString oldCandidateNames new HashSet(Arrays.asList(candidateNames));SetString alreadyParsedClasses new HashSet();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) !alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames newCandidateNames;}}while (!candidates.isEmpty());// Register the ImportRegistry as a bean in order to support ImportAware Configuration classesif (sbr ! null !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());}if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {// Clear cache in externally provided MetadataReaderFactory; this is a no-op// for a shared cache since itll be cleared by the ApplicationContext.((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();}
}上面源码中我们可以看出在注释标注的Parse each Configuration class的这一部分是主要用于处理配置类的关键代码就是使用了ConfigurationClassParser的parse方法parse方法会调用processConfigurationClass方法然后调用doProcessConfigurationClass方法在该方法里会统一处理Component、PropertySources以及ComponentScans的扫描、ImportResource。
// org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Setorg.springframework.beans.factory.config.BeanDefinitionHolder)
public void parse(SetBeanDefinitionHolder configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException(Failed to parse configuration class [ bd.getBeanClassName() ], ex);}}this.deferredImportSelectorHandler.process();
}1parse方法中Bean方法的处理
并且还会处理Bean标注的方法本文只分析Bean的处理在此截取doProcessConfigurationClass对Bean的处理部分
// Process individual Bean methods
SetMethodMetadata beanMethods retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}其中retrieveBeanMethodMetadata就是筛选出所有包含Bean的方法有个递归的过程
// org.springframework.context.annotation.ConfigurationClassParser#retrieveBeanMethodMetadata
private SetMethodMetadata retrieveBeanMethodMetadata(SourceClass sourceClass) {AnnotationMetadata original sourceClass.getMetadata();SetMethodMetadata beanMethods original.getAnnotatedMethods(Bean.class.getName());if (beanMethods.size() 1 original instanceof StandardAnnotationMetadata) {// Try reading the class file via ASM for deterministic declaration order...// Unfortunately, the JVMs standard reflection returns methods in arbitrary// order, even between different runs of the same application on the same JVM.try {AnnotationMetadata asm this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();SetMethodMetadata asmMethods asm.getAnnotatedMethods(Bean.class.getName());if (asmMethods.size() beanMethods.size()) {SetMethodMetadata selectedMethods new LinkedHashSet(asmMethods.size());for (MethodMetadata asmMethod : asmMethods) {for (MethodMetadata beanMethod : beanMethods) {if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {selectedMethods.add(beanMethod);break;}}}if (selectedMethods.size() beanMethods.size()) {// All reflection-detected methods found in ASM method set - proceedbeanMethods selectedMethods;}}}catch (IOException ex) {logger.debug(Failed to read class file via ASM for determining Bean method order, ex);// No worries, lets continue with the reflection metadata we started with...}}return beanMethods;
}
处理完retrieveBeanMethodMetadata方法之后将Bean的方法信息存入了configClass中。
2注册解析Bean标注的方法
// org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions
public void loadBeanDefinitions(SetConfigurationClass configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator new TrackedConditionEvaluator();for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}
}private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName configClass.getBeanName();if (StringUtils.hasLength(beanName) this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);}this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());return;}if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);}// 以下是用于处理Bean标注的方法的逻辑for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);}loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}我们继续看loadBeanDefinitionsForBeanMethod方法该方法就是对Bean标注的方法进行最终处理的逻辑
// org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {ConfigurationClass configClass beanMethod.getConfigurationClass();MethodMetadata metadata beanMethod.getMetadata();String methodName metadata.getMethodName();// Do we need to mark the bean as skipped by its condition?// 判断Conditionif (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {configClass.skippedBeanMethods.add(methodName);return;}if (configClass.skippedBeanMethods.contains(methodName)) {return;}// 再次校验是不是有Bean注解AnnotationAttributes bean AnnotationConfigUtils.attributesFor(metadata, Bean.class);Assert.state(bean ! null, No Bean annotation attributes);// Consider name and any aliasesListString names new ArrayList(Arrays.asList(bean.getStringArray(name)));String beanName (!names.isEmpty() ? names.remove(0) : methodName);// Register aliases even when overriddenfor (String alias : names) {this.registry.registerAlias(beanName, alias);}// Has this effectively been overridden before (e.g. via XML)?if (isOverriddenByExistingDefinition(beanMethod, beanName)) {if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),beanName, Bean name derived from Bean method beanMethod.getMetadata().getMethodName() clashes with bean name for containing configuration class; please make those names unique!);}return;}ConfigurationClassBeanDefinition beanDef new ConfigurationClassBeanDefinition(configClass, metadata);beanDef.setResource(configClass.getResource());beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));// 如果是静态方法不需要配置类先加载可以优先加载静态方法if (metadata.isStatic()) {// static Bean methodif (configClass.getMetadata() instanceof StandardAnnotationMetadata) {beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());}else {beanDef.setBeanClassName(configClass.getMetadata().getClassName());}beanDef.setUniqueFactoryMethodName(methodName);}else {// instance Bean method// 如果是实例方法会先关联配置类所以首先要配置类加载之后才能加载实例方法beanDef.setFactoryBeanName(configClass.getBeanName());beanDef.setUniqueFactoryMethodName(methodName);}if (metadata instanceof StandardMethodMetadata) {beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());}beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);// 处理其他属性Autowire autowire bean.getEnum(autowire);if (autowire.isAutowire()) {beanDef.setAutowireMode(autowire.value());}boolean autowireCandidate bean.getBoolean(autowireCandidate);if (!autowireCandidate) {beanDef.setAutowireCandidate(false);}String initMethodName bean.getString(initMethod);if (StringUtils.hasText(initMethodName)) {beanDef.setInitMethodName(initMethodName);}String destroyMethodName bean.getString(destroyMethod);beanDef.setDestroyMethodName(destroyMethodName);// Consider scopingScopedProxyMode proxyMode ScopedProxyMode.NO;AnnotationAttributes attributes AnnotationConfigUtils.attributesFor(metadata, Scope.class);if (attributes ! null) {beanDef.setScope(attributes.getString(value));proxyMode attributes.getEnum(proxyMode);if (proxyMode ScopedProxyMode.DEFAULT) {proxyMode ScopedProxyMode.NO;}}// Replace the original bean definition with the target one, if necessaryBeanDefinition beanDefToRegister beanDef;if (proxyMode ! ScopedProxyMode.NO) {BeanDefinitionHolder proxyDef ScopedProxyCreator.createScopedProxy(new BeanDefinitionHolder(beanDef, beanName), this.registry,proxyMode ScopedProxyMode.TARGET_CLASS);beanDefToRegister new ConfigurationClassBeanDefinition((RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);}if (logger.isTraceEnabled()) {logger.trace(String.format(Registering bean definition for Bean method %s.%s(),configClass.getMetadata().getClassName(), beanName));}this.registry.registerBeanDefinition(beanName, beanDefToRegister);
} 文章转载自: http://www.morning.dbqg.cn.gov.cn.dbqg.cn http://www.morning.sqnxk.cn.gov.cn.sqnxk.cn http://www.morning.pqyms.cn.gov.cn.pqyms.cn http://www.morning.hwbmn.cn.gov.cn.hwbmn.cn http://www.morning.rcyrm.cn.gov.cn.rcyrm.cn http://www.morning.zjqwr.cn.gov.cn.zjqwr.cn http://www.morning.kwpnx.cn.gov.cn.kwpnx.cn http://www.morning.hpprx.cn.gov.cn.hpprx.cn http://www.morning.dzrcj.cn.gov.cn.dzrcj.cn http://www.morning.bylzr.cn.gov.cn.bylzr.cn http://www.morning.wfysn.cn.gov.cn.wfysn.cn http://www.morning.zphlb.cn.gov.cn.zphlb.cn http://www.morning.qtltg.cn.gov.cn.qtltg.cn http://www.morning.hbdqf.cn.gov.cn.hbdqf.cn http://www.morning.tymnr.cn.gov.cn.tymnr.cn http://www.morning.qpnb.cn.gov.cn.qpnb.cn http://www.morning.xqcst.cn.gov.cn.xqcst.cn http://www.morning.cfccp.cn.gov.cn.cfccp.cn http://www.morning.tbqbd.cn.gov.cn.tbqbd.cn http://www.morning.nlcw.cn.gov.cn.nlcw.cn http://www.morning.hrjrt.cn.gov.cn.hrjrt.cn http://www.morning.tjwfk.cn.gov.cn.tjwfk.cn http://www.morning.oioini.com.gov.cn.oioini.com http://www.morning.lydtr.cn.gov.cn.lydtr.cn http://www.morning.dbfj.cn.gov.cn.dbfj.cn http://www.morning.wjplr.cn.gov.cn.wjplr.cn http://www.morning.cwwts.cn.gov.cn.cwwts.cn http://www.morning.bpmdq.cn.gov.cn.bpmdq.cn http://www.morning.kpbgp.cn.gov.cn.kpbgp.cn http://www.morning.nlglm.cn.gov.cn.nlglm.cn http://www.morning.tfzjl.cn.gov.cn.tfzjl.cn http://www.morning.pndhh.cn.gov.cn.pndhh.cn http://www.morning.gqcd.cn.gov.cn.gqcd.cn http://www.morning.tqxtx.cn.gov.cn.tqxtx.cn http://www.morning.ie-comm.com.gov.cn.ie-comm.com http://www.morning.ffhlh.cn.gov.cn.ffhlh.cn http://www.morning.mlcwl.cn.gov.cn.mlcwl.cn http://www.morning.rsfp.cn.gov.cn.rsfp.cn http://www.morning.jxgyg.cn.gov.cn.jxgyg.cn http://www.morning.rqxtb.cn.gov.cn.rqxtb.cn http://www.morning.ogzjf.cn.gov.cn.ogzjf.cn http://www.morning.ptwqf.cn.gov.cn.ptwqf.cn http://www.morning.lpnb.cn.gov.cn.lpnb.cn http://www.morning.tndhm.cn.gov.cn.tndhm.cn http://www.morning.mcfjq.cn.gov.cn.mcfjq.cn http://www.morning.ckrnq.cn.gov.cn.ckrnq.cn http://www.morning.dlrsjc.com.gov.cn.dlrsjc.com http://www.morning.sxmbk.cn.gov.cn.sxmbk.cn http://www.morning.qtzqk.cn.gov.cn.qtzqk.cn http://www.morning.qpqwd.cn.gov.cn.qpqwd.cn http://www.morning.gdgylp.com.gov.cn.gdgylp.com http://www.morning.wfhnz.cn.gov.cn.wfhnz.cn http://www.morning.rkdnm.cn.gov.cn.rkdnm.cn http://www.morning.jlgjn.cn.gov.cn.jlgjn.cn http://www.morning.fhrt.cn.gov.cn.fhrt.cn http://www.morning.dthyq.cn.gov.cn.dthyq.cn http://www.morning.mrxgm.cn.gov.cn.mrxgm.cn http://www.morning.ybgt.cn.gov.cn.ybgt.cn http://www.morning.lbssg.cn.gov.cn.lbssg.cn http://www.morning.mjats.com.gov.cn.mjats.com http://www.morning.krzrg.cn.gov.cn.krzrg.cn http://www.morning.dbnrl.cn.gov.cn.dbnrl.cn http://www.morning.tsnq.cn.gov.cn.tsnq.cn http://www.morning.mqdr.cn.gov.cn.mqdr.cn http://www.morning.mpflb.cn.gov.cn.mpflb.cn http://www.morning.zhengdaotang.cn.gov.cn.zhengdaotang.cn http://www.morning.wmmtl.cn.gov.cn.wmmtl.cn http://www.morning.fxqjz.cn.gov.cn.fxqjz.cn http://www.morning.nrqnj.cn.gov.cn.nrqnj.cn http://www.morning.pghry.cn.gov.cn.pghry.cn http://www.morning.rgpbk.cn.gov.cn.rgpbk.cn http://www.morning.mbfkt.cn.gov.cn.mbfkt.cn http://www.morning.glwyn.cn.gov.cn.glwyn.cn http://www.morning.gpxbc.cn.gov.cn.gpxbc.cn http://www.morning.mspqw.cn.gov.cn.mspqw.cn http://www.morning.jwcmq.cn.gov.cn.jwcmq.cn http://www.morning.qyfqx.cn.gov.cn.qyfqx.cn http://www.morning.rnht.cn.gov.cn.rnht.cn http://www.morning.bpmdx.cn.gov.cn.bpmdx.cn http://www.morning.hpnhl.cn.gov.cn.hpnhl.cn