当前位置: 首页 > news >正文

网站免费建设北京seo站内优化

网站免费建设,北京seo站内优化,推广策略包括哪些方面,网站拓扑图怎么做文章目录 一、目标:自动扫描Bean对象注册二、设计:自动扫描Bean对象注册三、实现:自动扫描Bean对象注册3.0 引入依赖3.1 工程结构3.2 Bean生命周期中自动加载包扫描注册Bean对象和设置占位符属性类图3.3 主力占位符配置3.4 定义拦截注解3.4.1…

文章目录

  • 一、目标:自动扫描Bean对象注册
  • 二、设计:自动扫描Bean对象注册
  • 三、实现:自动扫描Bean对象注册
    • 3.0 引入依赖
    • 3.1 工程结构
    • 3.2 Bean生命周期中自动加载包扫描注册Bean对象和设置占位符属性类图
    • 3.3 主力占位符配置
    • 3.4 定义拦截注解
      • 3.4.1 定义拦截注解
      • 3.4.2 定义注册注解
    • 3.5 处理对象扫描装配
      • 3.5.1 类路径扫描装配提供者类
      • 3.5.2 类路径扫描装配实现类
    • 3.6 解析xml中调用扫描
  • 四、测试:自动扫描Bean对象注册
    • 4.1 添加测试配置
      • 4.1.1 用户服务层实现类
      • 4.1.2 属性配置文件
      • 4.1.3 Spring属性配置文件
      • 4.1.4 Spring扫描配置文件
    • 4.2 单元测试
      • 4.2.1 占位符测试
      • 4.2.2 包扫描测试
  • 五、总结:自动扫描Bean对象注册

一、目标:自动扫描Bean对象注册

💡 怎么完成自动化扫描Bean对象,自动注册填充?

  • 早期的 Spring 版本,需要一个一个在 spring.xml 中进行配置。
  • 现在的 Spring 版本,在核心功能逻辑上建设的更少的配置下,做到更简化的使用。包括:包的扫描注册、注解配置的使用、占位符属性的填充等。
  • 目标:在目前的核心逻辑上填充一些自动化的功能。

二、设计:自动扫描Bean对象注册

💡 怎么简化 Bean 对象的配置?怎么让整个 Bean 对象的注册都是自动扫描的?

  • 需要的元素包括:扫描路径入口、XML 解析扫描信息、给需要扫描的 Bean 对象做注解标记、扫描 Class 对象摘取 Bean 注册的基本信息、组装注册信息、注册成 Bean 对象。
  • 在这些条件元素的支撑下,就可以实现出自定义注解和配置扫描路径的情况下,完成 Bean 对象的注册。
  • 除此之外再可以解决一个配置中占位符属性的知识点,
    • 比如:${token}Bean 对象注入进去属性信息,那么就需要用到 BeanFactoryPostProcessor
    • 因为它可以处理 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,提供修改 BeanDefinition 属性的机制
    • 而实现这部分内容是为了后续把此类内容结合到自动化配置处理中。

在这里插入图片描述

  • 结合 Bean 的生命周期,包扫描只不过是扫描特定注解的类,提取类的相关信息组装成 BeanDefinition 注册到容器中。
  • XmlBeanDefinitionReader 中解析 <context component-scan /> 标签,扫描类组装 BeanDefinition 然后注册到容器中的操作在 ClassPathBeanDefinitionScanner#doScan 中实现。
    • 自动扫描注册:主要是扫描添加了自定义注解的类,在 xml 加载过程中提取类的信息,组装 BeanDefinition 注册到 Spring 容器中。
    • 需要用到 <context component-scan />:配置包路径并在 XmlBeanDefinitionReader 解析并做相应的处理(对类的扫描、获取注解信息等)。
    • 最后包括了 BeanFactoryPostProcessor 的使用。因为我们需要完成对占位符配置信息的加载,所以需要使用到 BeanFactoryPostProcessor 在所有的 BeanDefinition 加载完成后,实例化 Bean 对象之前,修改 BeanDefinition 的属性信息。

三、实现:自动扫描Bean对象注册

3.0 引入依赖

pom.xml

<!-- https://mvnrepository.com/artifact/org.dom4j/dom4j -->
<dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.3</version>
</dependency>

3.1 工程结构

spring-step-12
|-src|-main|	|-java|		|-com.lino.springframework|			|-aop|			|	|-aspectj|			|	|	|-AspectJExpressionPointcut.java|			|	|	|-AspectJExpressionPointcutAdvisor.java|			|	|-framework|			|	|	|-adapter|			|	|	|	|-MethodBeforeAdviceInterceptor.java|			|	|	|-autoproxy|			|	|	|	|-DefaultAdvisorAutoProxyCreator.java|			|	|	|-AopProxy.java|			|	|	|-Cglib2AopProxy.java|			|	|	|-JdkDynamicAopProxy.java|			|	|	|-ProxyFactory.java|			|	|	|-ReflectiveMethodInvocation.java|			|	|-AdvisedSupport.java|			|	|-Advisor.java|			|	|-BeforeAdvice.java|			|	|-ClassFilter.java|			|	|-MethodBeforeAdvice.java|			|	|-MethodMatcher.java|			|	|-Pointcut.java|			|	|-PointcutAdvisor.java|			|	|-TargetSource.java|			|-beans|			|	|-factory|			|	|	|-config|			|	|	|	|-AutowireCapableBeanFactory.java|			|	|	|	|-BeanDefinition.java|			|	|	|	|-BeanFactoryPostProcessor.java|			|	|	|	|-BeanPostProcessor.java|			|	|	|	|-BeanReference.java|			|	|	|	|-ConfigurableBeanFactory.java|			|	|	|	|-InstantiationAwareBeanPostProcessor.java|			|	|	|	|-SingletonBeanRegistry.java|			|	|	|-support|			|	|	|	|-AbstractAutowireCapableBeanFactory.java|			|	|	|	|-AbstractBeabDefinitionReader.java|			|	|	|	|-AbstractBeabFactory.java|			|	|	|	|-BeabDefinitionReader.java|			|	|	|	|-BeanDefinitionRegistry.java|			|	|	|	|-CglibSubclassingInstantiationStrategy.java|			|	|	|	|-DefaultListableBeanFactory.java|			|	|	|	|-DefaultSingletonBeanRegistry.java|			|	|	|	|-DisposableBeanAdapter.java|			|	|	|	|-FactoryBeanRegistrySupport.java|			|	|	|	|-InstantiationStrategy.java|			|	|	|	|-SimpleInstantiationStrategy.java|			|	|	|-xml|			|	|	|	|-XMLBeanDefinitionReader.java|			|	|	|-Aware.java|			|	|	|-BeanClassLoaderAware.java|			|	|	|-BeanFactory.java|			|	|	|-BeanFactoryAware.java|			|	|	|-BeanNameAware.java|			|	|	|-ConfigurableListableBeanFactory.java|			|	|	|-DisposableBean.java|			|	|	|-FactoryBean.java|			|	|	|-HierarcgicalBeanFactory.java|			|	|	|-InitializingBean.java|			|	|	|-ListableBeanFactory.java|			|	|	|-PropertyPlaceholderConfigurer.java|			|	|-BeansException.java|			|	|-PropertyValue.java|			|	|-PropertyValues.java|			|-context|			|	|-annotation|			|	|	|-ClassPathBeanDefinitionScanner.java|			|	|	|-ClassPathScanningCandidateComponentProvider.java|			|	|	|-Scope.java|			|	|-event|			|	|	|-AbstractApplicationEventMulticaster.java|			|	|	|-ApplicationContextEvent.java|			|	|	|-ApplicationEventMulticaster.java|			|	|	|-ContextclosedEvent.java|			|	|	|-ContextRefreshedEvent.java|			|	|	|-SimpleApplicationEventMulticaster.java|			|	|-support|			|	|	|-AbstractApplicationContext.java|			|	|	|-AbstractRefreshableApplicationContext.java|			|	|	|-AbstractXmlApplicationContext.java|			|	|	|-ApplicationContextAwareProcessor.java|			|	|	|-ClassPathXmlApplicationContext.java|			|	|-ApplicationContext.java|			|	|-ApplicationContextAware.java|			|	|-ApplicationEvent.java|			|	|-ApplicationEventPublisher.java|			|	|-ApplicationListener.java|			|	|-ConfigurableApplicationContext.java|			|-core.io|			|	|-ClassPathResource.java|			|	|-DefaultResourceLoader.java|			|	|-FileSystemResource.java|			|	|-Resource.java|			|	|-ResourceLoader.java|			|	|-UrlResource.java|			|-stereotype|			|	|-Component.java|			|-util|			|	|-ClassUtils.java|-test|-java|-com.lino.springframework.test|-bean|	|-IUserService.java|	|-UserService.java|-ApiTest.java|-resources|-spring-property.xml|-spring-scan.xml|-token.properties

3.2 Bean生命周期中自动加载包扫描注册Bean对象和设置占位符属性类图

在这里插入图片描述

  • 整个类图看,主要包括的就是 xml 解析类 XmlBeanDefinitionReaderClassPathBeanDefinitionScanner#doScan 的使用。
  • doScan 方法中处理所有指定路径下添加了注解的类,拆解出类的信息:名称、作用范围等,进行创建 BeanDefinition 好用于 Bean 对象的注册操作。
  • PropertyPlaceholderConfigurer 后续会与自动加载 Bean 对象进行整合,也就是可以在注解上使用占位符配置一些在配置文件里的属性信息。

3.3 主力占位符配置

PropertyPlaceholderConfigurer.java

package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanFactoryPostProcessor;
import com.lino.springframework.core.io.DefaultResourceLoader;
import com.lino.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Properties;/*** @description: 处理占位符配置类*/
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {/*** 占位符前缀*/public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";/*** 占位符后缀*/public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";private String location;@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 加载属性文件try {DefaultResourceLoader resourceLoader = new DefaultResourceLoader();Resource resource = resourceLoader.getResource(location);Properties properties = new Properties();properties.load(resource.getInputStream());String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanDefinitionNames) {BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);PropertyValues propertyValues = beanDefinition.getPropertyValues();for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {Object value = propertyValue.getValue();if (!(value instanceof String)) {continue;}String strVal = (String) value;StringBuilder buffer = new StringBuilder(strVal);int startIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX);int stopIdx = strVal.indexOf(DEFAULT_PLACEHOLDER_SUFFIX);if (startIdx != -1 && stopIdx != -1 && startIdx < stopIdx) {String propKey = strVal.substring(startIdx + 2, stopIdx);String propVal = properties.getProperty(propKey);buffer.replace(startIdx, stopIdx + 1, propVal);propertyValues.addPropertyValue(new PropertyValue(propertyValue.getName(), buffer.toString()));}}}} catch (IOException e) {throw new BeansException("Could not load properties", e);}}public void setLocation(String location) {this.location = location;}
}
  • 依赖于 BeanFactoryPostProcessorBean 生命周期的属性,可以在 Bean 对象实例化之前,改变属性信息。
    • 所以这里通过实现 BeanFactoryPostProcessor 接口,完成对配置文件的加载以及摘取占位符在属性文件中的配置。
  • 这样可以把提取到的配置信息放置到属性信息中:
    • buffer.replace(startIdx, stopIdx + 1, propVal)propertyValues.addPropertyValue

3.4 定义拦截注解

3.4.1 定义拦截注解

Scope.java

package com.lino.springframework.context.annotation;import java.lang.annotation.*;/*** @description: 拦截注解*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {String value() default "singleton";
}
  • 用于配置作用域的自定义注解,方便通过配置 Bean 对象注解的时候,拿到 Bean 对象的作用域。

3.4.2 定义注册注解

Component.java

package com.lino.springframework.stereotype;import java.lang.annotation.*;/*** @description: 注册注解*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {String value() default "";
}
  • Component 自定义注解,用于配置到 Class 类上。

3.5 处理对象扫描装配

3.5.1 类路径扫描装配提供者类

ClassPathScanningCandidateComponentProvider.java

package com.lino.springframework.context.annotation;import cn.hutool.core.util.ClassUtil;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.stereotype.Component;
import java.util.LinkedHashSet;
import java.util.Set;/*** @description: 类路径扫描装配提供者*/
public class ClassPathScanningCandidateComponentProvider {public Set<BeanDefinition> findCandidateComponents(String basePackages) {Set<BeanDefinition> candidates = new LinkedHashSet<>();Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation(basePackages, Component.class);for (Class<?> clazz : classes) {candidates.add(new BeanDefinition(clazz));}return candidates;}
}
  • 这里先要提供一个可以通过配置路径 beanPackage=com.lino.springframework.test.bean,解析出 classes 信息的工具方法 findCandidateComponents,通过这个方法就可以扫描到所有 @Component 注解的 Bean 对象。

3.5.2 类路径扫描装配实现类

ClassPathBeanDefinitionScanner.java

package com.lino.springframework.context.annotation;import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.stereotype.Component;
import java.util.Set;/*** @description: 类路径扫描装配实现类*/
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {private BeanDefinitionRegistry registry;public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {this.registry = registry;}public void doScan(String... basePackages) {for (String basePackage : basePackages) {Set<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition beanDefinition : candidates) {// 解析 bean 的作用域 singleton、prototypeString beanScope = resolveBeanScope(beanDefinition);if (StrUtil.isNotEmpty(beanScope)) {beanDefinition.setScope(beanScope);}registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);}}}private String resolveBeanScope(BeanDefinition beanDefinition) {Class<?> beanClass = beanDefinition.getBeanClass();Scope scope = beanClass.getAnnotation(Scope.class);if (null != scope) {return scope.value();}return StrUtil.EMPTY;}private String determineBeanName(BeanDefinition beanDefinition) {Class<?> beanClass = beanDefinition.getBeanClass();Component component = beanClass.getAnnotation(Component.class);String value = component.value();if (StrUtil.isEmpty(value)) {value = StrUtil.lowerFirst(beanClass.getSimpleName());}return value;}
}
  • ClassPathBeanDefinitionScanner 是继承自 ClassPathScanningCandidateComponentProvider 的具体扫描包处理的类,在 doScan 中获取到扫描的类信息后,还需要获取 Bean 的作用域和类名,如果不配置类名基本都是把首字母缩写。

3.6 解析xml中调用扫描

XmlBeanDefinitionReader.java

package com.lino.springframework.beans.factory.xml;import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.factory.config.BeanDefinition;
import com.lino.springframework.beans.factory.config.BeanReference;
import com.lino.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import com.lino.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.lino.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import com.lino.springframework.core.io.Resource;
import com.lino.springframework.core.io.ResourceLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;/*** @description: XML处理Bean注册*/
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {...@Overridepublic void loadBeanDefinitions(Resource resource) throws BeansException {try {try (InputStream inputStream = resource.getInputStream()) {doLoadBeanDefinitions(inputStream);}} catch (IOException | ClassNotFoundException | DocumentException e) {throw new BeansException("IOException parsing XML document from " + resource, e);}}...protected void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, DocumentException {SAXReader reader = new SAXReader();Document document = reader.read(inputStream);Element root = document.getRootElement();// 解析 context:component-scan标签,扫描包中的类并提取相关信息,用于组装 BeanDefinitionElement componentScan = root.element("component-scan");if (null != componentScan) {String scanPath = componentScan.attributeValue("base-package");if (StrUtil.isEmpty(scanPath)) {throw new BeansException("The value of base-package attribute can not be empty or null");}scanPackage(scanPath);}List<Element> beanList = root.elements("bean");for (Element bean : beanList) {String id = bean.attributeValue("id");String name = bean.attributeValue("name");String className = bean.attributeValue("class");String initMethod = bean.attributeValue("init-method");String destroyMethodName = bean.attributeValue("destroy-method");String beanScope = bean.attributeValue("scope");// 获取 Class, 方便获取类中的名称Class<?> clazz = Class.forName(className);// 优先级 id > nameString beanName = StrUtil.isNotEmpty(id) ? id : name;if (StrUtil.isEmpty(beanName)) {beanName = StrUtil.lowerFirst(clazz.getSimpleName());}// 定义beanBeanDefinition beanDefinition = new BeanDefinition(clazz);beanDefinition.setInitMethodName(initMethod);beanDefinition.setDestroyMethodName(destroyMethodName);if (StrUtil.isNotEmpty(beanScope)) {beanDefinition.setScope(beanScope);}List<Element> propertyList = bean.elements("property");// 读取属性并填充for (Element property : propertyList) {// 解析标签:propertyString attrName = property.attributeValue("name");String attrValue = property.attributeValue("value");String attrRef = property.attributeValue("ref");// 获取属性值:引入对象、值对象Object value = StrUtil.isNotEmpty(attrRef) ? new BeanReference(attrRef) : attrValue;// 创建属性信息PropertyValue propertyValue = new PropertyValue(attrName, value);beanDefinition.getPropertyValues().addPropertyValue(propertyValue);}if (getRegistry().containsBeanDefinition(beanName)) {throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");}// 注册 BeanDefinitiongetRegistry().registerBeanDefinition(beanName, beanDefinition);}}private void scanPackage(String scanPath) {String[] basePackages = StrUtil.splitToArray(scanPath, ',');ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(getRegistry());scanner.doScan(basePackages);}
}
  • XmlBeanDefinitionReader 主要是在加载配置文件后,处理新增的自定义配置属性 component-scan,解析后调用 scanPackage 方法。
    • 其实就是 ClassPathBeanDefinitionScanner#doScan 方法。
  • 为了方便加载和解析 xml,XmlBeanDefinitionReader 替换为 dom4j 进行解析处理。

四、测试:自动扫描Bean对象注册

4.1 添加测试配置

4.1.1 用户服务层实现类

UserService.java

package com.lino.springframework.test.bean;import com.lino.springframework.stereotype.Component;import java.util.Random;/*** @description: 用户接口实现类*/
@Component("userService")
public class UserService implements IUserService {private String token;@Overridepublic String queryUserInfo() {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return "张三,100001,杭州";}@Overridepublic String register(String userName) {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return "注册用户:" + userName + " success!";}@Overridepublic String toString() {return "UserService#token = {" + token + "}";}public String getToken() {return token;}public void setToken(String token) {this.token = token;}
}
  • UserService 添加了一个自定义注解 @Component("userService") 和一个属性信息 String token

4.1.2 属性配置文件

token.properties

token=RejDlI78hu223Opo983Ds
  • 这里配置一个 token 属性信息,通过占位符的方式进行获取。

4.1.3 Spring属性配置文件

spring-property.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.lino.springframework.beans.factory.PropertyPlaceholderConfigurer"><property name="location" value="classpath:token.properties"/></bean><bean id="userService" class="com.lino.springframework.test.bean.UserService"><property name="token" value="${token}"/></bean></beans>
  • 加载 classpath:token.properties 设置占位符属性值 ${token}

4.1.4 Spring扫描配置文件

spring-scan.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context"><context:component-scan base-package="com.lino.springframework.test.bean"/></beans>
  • 添加 component-scan 属性,设置包扫描根路径。

4.2 单元测试

4.2.1 占位符测试

ApiTest.java

@Test
public void test_property() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-property.xml");IUserService userService = applicationContext.getBean("userService", IUserService.class);System.out.println("测试结果:" + userService);
}

测试结果

测试结果:UserService#token = {RejDlI78hu223Opo983Ds}
  • 通过测试结果看,UserServicetoken 属性已经通过占位符的方式设置进去配置文件里的 token.properties 的属性值了。

4.2.2 包扫描测试

ApiTest.java

@Test
public void test_scan() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-scan.xml");IUserService userService = applicationContext.getBean("userService", IUserService.class);System.out.println("测试结果:" + userService.queryUserInfo());
}

测试结果

测试结果:张三,100001,杭州
  • 测试结果看,现在使用注解的方式就可以让 Class 注册完成 Bean 对象了。

五、总结:自动扫描Bean对象注册

  • 通过整篇的内容实现来看,目前的功能添加其实不是很复杂,都是在 IOCAOP 核心的基础上来补全功能。这些补全的功能也是在完善 Bean 的生命周期,让整个功能使用越来越容易。

文章转载自:
http://exuviate.tgnr.cn
http://unacquirable.tgnr.cn
http://haggish.tgnr.cn
http://literalness.tgnr.cn
http://optionee.tgnr.cn
http://existential.tgnr.cn
http://threesome.tgnr.cn
http://wiener.tgnr.cn
http://bailor.tgnr.cn
http://volubility.tgnr.cn
http://bacteremically.tgnr.cn
http://heliotaxis.tgnr.cn
http://earlap.tgnr.cn
http://plumbicon.tgnr.cn
http://winterkill.tgnr.cn
http://sylvester.tgnr.cn
http://doable.tgnr.cn
http://uncleanness.tgnr.cn
http://sof.tgnr.cn
http://messin.tgnr.cn
http://scissel.tgnr.cn
http://cid.tgnr.cn
http://actable.tgnr.cn
http://plaintful.tgnr.cn
http://cephalometer.tgnr.cn
http://muss.tgnr.cn
http://audiometry.tgnr.cn
http://particularism.tgnr.cn
http://biliprotein.tgnr.cn
http://mangosteen.tgnr.cn
http://dehydroisoandrosterone.tgnr.cn
http://jap.tgnr.cn
http://pruth.tgnr.cn
http://overshirt.tgnr.cn
http://twifold.tgnr.cn
http://buitenzorg.tgnr.cn
http://allision.tgnr.cn
http://mediaevalist.tgnr.cn
http://possibility.tgnr.cn
http://shall.tgnr.cn
http://eponymist.tgnr.cn
http://kinetic.tgnr.cn
http://feckless.tgnr.cn
http://duchy.tgnr.cn
http://bactericide.tgnr.cn
http://lasher.tgnr.cn
http://nascence.tgnr.cn
http://infinitive.tgnr.cn
http://placoderm.tgnr.cn
http://delegitimation.tgnr.cn
http://alumnus.tgnr.cn
http://soogan.tgnr.cn
http://undrape.tgnr.cn
http://reinvition.tgnr.cn
http://yahwist.tgnr.cn
http://schistorrhachis.tgnr.cn
http://farrand.tgnr.cn
http://calibrator.tgnr.cn
http://heliochromy.tgnr.cn
http://hectostere.tgnr.cn
http://pultaceous.tgnr.cn
http://blimp.tgnr.cn
http://teutomaniac.tgnr.cn
http://gironny.tgnr.cn
http://stockbreeder.tgnr.cn
http://dogcart.tgnr.cn
http://deutoplasm.tgnr.cn
http://myelofibrosis.tgnr.cn
http://bojardo.tgnr.cn
http://zoogeny.tgnr.cn
http://geometrism.tgnr.cn
http://rebus.tgnr.cn
http://polychaetan.tgnr.cn
http://haemophilic.tgnr.cn
http://accouterment.tgnr.cn
http://landownership.tgnr.cn
http://antineutron.tgnr.cn
http://ferned.tgnr.cn
http://height.tgnr.cn
http://tacker.tgnr.cn
http://doolie.tgnr.cn
http://uncio.tgnr.cn
http://intellectualize.tgnr.cn
http://hangzhou.tgnr.cn
http://formal.tgnr.cn
http://corndodger.tgnr.cn
http://mastersinger.tgnr.cn
http://diaphototropism.tgnr.cn
http://comtism.tgnr.cn
http://scald.tgnr.cn
http://alienated.tgnr.cn
http://thermophysics.tgnr.cn
http://cheetah.tgnr.cn
http://craftswoman.tgnr.cn
http://indecency.tgnr.cn
http://heinously.tgnr.cn
http://sunburnt.tgnr.cn
http://imagination.tgnr.cn
http://modeless.tgnr.cn
http://trangam.tgnr.cn
http://www.15wanjia.com/news/76928.html

相关文章:

  • 棋牌类网站是用游戏方式做的吗市场推广方式有哪几种
  • 济南汽车网站设计seo网站排名
  • 保定网站seo费用今日十大新闻
  • 网易游戏成都网站优化排名推广
  • 如何访问自己做的网站百度爱采购优化软件
  • 九江网络营销百度seo排名优化教程
  • 网站建设后台中国今日新闻
  • 自学建百度首页网站百度快速排名优化服务
  • wordpress 做仿站广州今天刚刚发生的重大新闻
  • 简述电子商务网站的内容设计与开发排名推广网站
  • php动态网站开发课后详细描述如何进行搜索引擎的优化
  • 外贸网站推广有哪些seo如何去做优化
  • 朋友圈h5页面制作上海站群优化
  • 朝阳区网站建设重庆seo网络优化师
  • 中江县建设局网站5月疫情第二波爆发
  • 专业医疗网站建设西安百度公司地址介绍
  • 利用织梦搭网站怎么在百度上做公司网页
  • 网站建设需要多少钱小江成都网站建设公司
  • ui是做网站的吗指数基金有哪些
  • 互联网公司排名 中国杭州seo中心
  • 泰然建设网站客服系统网页源码2022免费
  • 购物网站开发的业务需求分析seo是什么东西
  • 广告公司实践报告3000字seo网站优化课程
  • 网站地址怎么做超链接百度打开
  • 用服务器ip做网站域名百度查重免费
  • 提高网站打开速度的7大秘籍智能搜索引擎
  • 橱柜衣柜做网站天津百度整站优化服务
  • 音乐网站开发答辩ppt店铺推广软文范例
  • 百度电脑网页版北京seo优化排名
  • 成都兼职做网站关键词推广排名软件