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

中恒诚信建设有限公司网站360街景地图最新版

中恒诚信建设有限公司网站,360街景地图最新版,能连接wordpress的app,vs做网站不用建项目参考文章#xff1a; 《Spring事务源码解析之tx:annotation-driven标签解析》 《Spring 源码解析—事务执行》 参考资料#xff1a; 《Spring AOP源码#xff1a;开启注解读取》 《Spring AOP源码2#xff1a;查找增强器》 《Spring AOP源码3#xff1a;实现代理》 …参考文章 《Spring事务源码解析之tx:annotation-driven标签解析》 《Spring 源码解析—事务执行》 参考资料 《Spring AOP源码开启注解读取》 《Spring AOP源码2查找增强器》 《Spring AOP源码3实现代理》 写在开头本文为个人学习笔记内容比较随意夹杂个人理解如有错误欢迎指正。 前言 本文我们介绍下Spring中的事务管理的源码Spring的事务管理主要有申明式事务与编程式事务这两种如果对这两种方式不了解的朋友可以先看下这篇文章《Spring事务管理详解实例》然后再来深入源码分析。 我们通过如下方式开启事务由于申明式事务的注入方式式基于代理方式实现的因此这里也建议先了解下AOP的源码这部分我前文已经做了完整的介绍因此下文将不会对AOP的功能做深入的解析有需要的朋友可以看下我之前AOP的文章。 tx:annotation-driven transaction-managertransactionManager/ bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource/ /bean目录 前言 一、AnnotationDrivenBeanDefinitionParser 1、TxNamespaceHandler 2、AnnotationDrivenBeanDefinitionParser 二、、AopAutoProxyConfigurer 1、注册自动代理创建器 1.1、注册InfrastructureAdvisorAutoProxyCreator 1.2、设置proxy-target-class和expose-proxy属性 1.3、注册ComponentDefinition 2、注册了事务管理器等Bean 2.1、创建AnnotationTransactionAttributeSource 2.2、创建TransactionInterceptor 2.3、创建BeanFactoryTransactionAttributeSourceAdvisor 三、代理对象的创建 1、InfrastructureAdvisorAutoProxyCreator 2、canapply 2.1、getMethodMatcher 2.2、getTransactionAttribute  2.3、computeTransactionAttribute 2.4、findTransactionAttribute 2.5、parseTransactionAnnotation 补充 事务仅对 public 方法有效 一、AnnotationDrivenBeanDefinitionParser 在介绍IOC时我们讲过Spring通过spring.handlers配置文件处理自定义命名空间节点《Spring IOCparseCustomElement调用链》从下面的配置中可以看出TX标签由TxNamespaceHandler类解析。 http\://www.springframework.org/schema/txorg.springframework.transaction.config.TxNamespaceHandler 1、TxNamespaceHandler TxNamespaceHandler中的init方法针对不通的属性配置实例化不通的解析对象这里我们使用了annotation-driven因此实例化的对象为AnnotationDrivenBeanDefinitionParser。 Overridepublic void init() {registerBeanDefinitionParser(advice, new TxAdviceBeanDefinitionParser());registerBeanDefinitionParser(annotation-driven, new AnnotationDrivenBeanDefinitionParser());registerBeanDefinitionParser(jta-transaction-manager, new JtaTransactionManagerBeanDefinitionParser());} 2、AnnotationDrivenBeanDefinitionParser 下面就来到了AnnotationDrivenBeanDefinitionParser的parse方法因为Spring事务管理也是基于创建代理类来实现的因此和AOP一样首先需要创建代理创建器。 Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {registerTransactionalEventListenerFactory(parserContext);String mode element.getAttribute(mode);// 判断是否配置了mode属性且为aspectj满足条件则走aop切面的方式管理事务if (aspectj.equals(mode)) {registerTransactionAspect(element, parserContext);}else {// 默认方式配置自动代理创建器AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);}return null;} 二、、AopAutoProxyConfigurer 创建代理创建器的流程可以拆解成如下几个步骤我们下面分别对其进行分析。 private static class AopAutoProxyConfigurer {public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {1、注册自动代理创建器2、注册了事务管理器等Bean }} 1、注册自动代理创建器 configureAutoProxyCreator调用registerAutoProxyCreatorIfNecessary注册自动代理创建器 public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {// 1、创建代理创建器AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);2、注册了AnnotationTransactionAttributeSource、TransactionInterceptor和BeanFactoryTransactionAttributeSourceAdvisor } registerAutoProxyCreatorIfNecessary分为三个步骤 1注册InfrastructureAdvisorAutoProxyCreator 2设置proxy-target-class和expose-proxy属性 3注册ComponentDefinition public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {// 向容器中注册InfrastructureAdvisorAutoProxyCreatorBeanDefinition beanDefinition AopConfigUtils.registerAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 设置proxy-target-class和expose-proxy配置useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);// 注册ComponentDefinitionregisterComponentIfNecessary(beanDefinition, parserContext);} 1.1、注册InfrastructureAdvisorAutoProxyCreator 很简单的方法向容器中注册固定的BeanDefinition。 public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);} 1.2、设置proxy-target-class和expose-proxy属性 解析标签中的proxy-target-class和expose-proxy属性值。proxy-target-class主要控制是使用Jdk代理还是Cglib代理实现expose-proxy用于控制是否将生成的代理类的实例防御AopContext中并且暴露给相关子类使用。 public static final String PROXY_TARGET_CLASS_ATTRIBUTE proxy-target-class;private static final String EXPOSE_PROXY_ATTRIBUTE expose-proxy;private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {if (sourceElement ! null) {boolean proxyTargetClass Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}boolean exposeProxy Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));if (exposeProxy) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}} 1.3、注册ComponentDefinition public static final String AUTO_PROXY_CREATOR_BEAN_NAME org.springframework.aop.config.internalAutoProxyCreator;private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {if (beanDefinition ! null) {parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));}} 2、注册了事务管理器等Bean public static final String TRANSACTION_ADVISOR_BEAN_NAME org.springframework.transaction.config.internalTransactionAdvisor;public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);//1、注册自动代理创建器AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);// 判断容器中有无internalTransactionAdvisorString txAdvisorBeanName TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {//2、注册了事务管理器等Bean 创建AnnotationTransactionAttributeSource创建TransactionInterceptor创建BeanFactoryTransactionAttributeSourceAdvisor}}} 2.1、创建AnnotationTransactionAttributeSource Object eleSource parserContext.extractSource(element); // 创建并注册AnnotationTransactionAttributeSource的BeanDefinition RootBeanDefinition sourceDef new RootBeanDefinition( org.springframework.transaction.annotation.AnnotationTransactionAttributeSource); sourceDef.setSource(eleSource); sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); String sourceName parserContext.getReaderContext().registerWithGeneratedName(sourceDef); 2.2、创建TransactionInterceptor 这一步创建了TransactionInterceptor的BeanDefinition并将上一步创建的AnnotationTransactionAttributeSource作为transactionAttributeSource属性注入了进去这个属性后面创建代理类的时候将会用到。 另外调用了registerTransactionManager创建了事务管理器。 RootBeanDefinition interceptorDef new RootBeanDefinition(TransactionInterceptor.class); interceptorDef.setSource(eleSource); interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registerTransactionManager(element, interceptorDef); interceptorDef.getPropertyValues().add(transactionAttributeSource, new RuntimeBeanReference(sourceName)); String interceptorName parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); registerTransactionManager创建了事务管理器其实就是添加事务管理器的beanName。 private static void registerTransactionManager(Element element, BeanDefinition def) {def.getPropertyValues().add(transactionManagerBeanName,TxNamespaceHandler.getTransactionManagerName(element));} 事务管理器的beanName在不指定transaction-manager属性的时候会默认寻找id固定名为transactionManager的bean作为事务管理器。 // TxNamespaceHandler.javastatic final String TRANSACTION_MANAGER_ATTRIBUTE transaction-manager;static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME transactionManager;static String getTransactionManagerName(Element element) {return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);} 2.3、创建BeanFactoryTransactionAttributeSourceAdvisor 创建BeanFactoryTransactionAttributeSourceAdvisor的BeanDefinition同时将前两个步骤中创建的AnnotationTransactionAttributeSource、TransactionInterceptor作为属性添加到当前Bean中最后注册到容器中。 RootBeanDefinition advisorDef new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); advisorDef.setSource(eleSource); advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); advisorDef.getPropertyValues().add(transactionAttributeSource, new RuntimeBeanReference(sourceName)); advisorDef.getPropertyValues().add(adviceBeanName, interceptorName); if (element.hasAttribute(order)) {dvisorDef.getPropertyValues().add(order, element.getAttribute(order));} parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef); 总结一下这两部其实主要是注册了InfrastructureAdvisorAutoProxyCreator与BeanFactoryTransactionAttributeSourceAdvisor可以从名字看出来一个是代理自动创建器一个是增强器。 三、代理对象的创建 1、InfrastructureAdvisorAutoProxyCreator InfrastructureAdvisorAutoProxyCreator类的继承关系如下图可以发现其和我们之前介绍AOP时提到的AnnotationAwareAspectJAutoProxyCreator一样继承了AbstractAdvisorAutoProxyCreator。 抽象类AbstractAdvisorAutoProxyCreator继承了BeanPostProcessor接口因此在Bean实例化的时候会去为其创建代理对象。这部分内容如果不熟悉可以看下我之前的文章《Spring IOCbean的生命周期与Autowire3》、《Spring AOP源码2查找增强器》 Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean ! null) {// 如果是普通bean则返回beanName如果是FactoryBean,则返回加上前缀的beanNameObject cacheKey getCacheKey(bean.getClass(), beanName);// 判断当前bean是否需要被代理如果需要则进行封装earlyProxyReferences中缓存的是已经创建好的代理对象if (!this.earlyProxyReferences.contains(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean; } 2、canapply 在创建代理类时会先查找能够应用在当前bean上的增强器这部分内容我们前文有过介绍就不赘述了这里直接从如何判断是否适配的判断方法canapply来讲起。 public static boolean canApply(Advisor advisor, Class? targetClass, boolean hasIntroductions) {// 判断引介增强是否匹配if (advisor instanceof IntroductionAdvisor) {return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);}else if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca (PointcutAdvisor) advisor;/* 判断当前增强是否可以应用在当前bean上 */return canApply(pca.getPointcut(), targetClass, hasIntroductions);}else {return true;} }这里的advisor就是我们的增强器BeanFactoryTransactionAttributeSourceAdvisor而pca.getPointcut()就是获取其内部创建的TransactionAttributeSourcePointcut。 Overridepublic Pointcut getPointcut() {return this.pointcut;}private final TransactionAttributeSourcePointcut pointcut new TransactionAttributeSourcePointcut() {Overrideprotected TransactionAttributeSource getTransactionAttributeSource() {return transactionAttributeSource;}}; 该对象重写了getTransactionAttributeSource方法获取的就是BeanFactoryTransactionAttributeSourceAdvisor在注册时添加的transactionAttributeSource属性其实现类为AnnotationTransactionAttributeSource。  // configureAutoProxyCreator方法RootBeanDefinition sourceDef new RootBeanDefinition(org.springframework.transaction.annotation.AnnotationTransactionAttributeSource);sourceDef.setSource(eleSource);sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);String sourceName parserContext.getReaderContext().registerWithGeneratedName(sourceDef);advisorDef.getPropertyValues().add(transactionAttributeSource, new RuntimeBeanReference(sourceName));继续往下深入调用pc.getMethodMatcher()获取方法匹配器这里的pc就是上文中的TransactionAttributeSourcePointcut类。 public static boolean canApply(Pointcut pc, Class? targetClass, boolean hasIntroductions) {Assert.notNull(pc, Pointcut must not be null);// 获取当前Advisor的CalssFilter并且调用其matches()方法判断当前切点表达式是否与目标bean匹配// 这里ClassFilter指代的切点表达式主要是当前切面类上使用的Aspect注解中所指代的切点表达式if (!pc.getClassFilter().matches(targetClass)) {return false;}// 判断如果当前Advisor所指代的方法的切点表达式如果是对任意方法都放行则直接返回MethodMatcher methodMatcher pc.getMethodMatcher();if (methodMatcher MethodMatcher.TRUE) {// No need to iterate the methods if were matching any method anyway...return true;}IntroductionAwareMethodMatcher introductionAwareMethodMatcher null;if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher (IntroductionAwareMethodMatcher) methodMatcher;}// 获取目标类的所有接口SetClass? classes new LinkedHashSetClass?(ClassUtils.getAllInterfacesForClassAsSet(targetClass));classes.add(targetClass);// 遍历目标类上的接口方法for (Class? clazz : classes) {Method[] methods ReflectionUtils.getAllDeclaredMethods(clazz);for (Method method : methods) {// 使用matches判断能否作用于该方法上if ((introductionAwareMethodMatcher ! null introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||methodMatcher.matches(method, targetClass)) {return true;}}}return false;} 2.1、getMethodMatcher TransactionAttributeSourcePointcut的getMethodMatcher方法是在它的父类StaticMethodMatcherPointcut中实现的。 public final MethodMatcher getMethodMatcher() {return this; }该方法直接返回了this也就是下面methodMatcher.matches方法就是调用TransactionAttributeSourcePointcut的matches方法。getTransactionAttributeSource即我们之前说过的AnnotationTransactionAttributeSourcegetTransactionAttribute则是调用的其父类AbstractFallbackTransactionAttributeSource的方法。 public boolean matches(Method method, Class? targetClass) {if (TransactionalProxy.class.isAssignableFrom(targetClass)) {return false;}TransactionAttributeSource tas getTransactionAttributeSource();return (tas null || tas.getTransactionAttribute(method, targetClass) ! null); }2.2、getTransactionAttribute  getTransactionAttribute中判断有无缓存如果缓存不存在则调用computeTransactionAttribute方法查找事务属性获取后进行缓存。 public TransactionAttribute getTransactionAttribute(Method method, Class? targetClass) {if (method.getDeclaringClass() Object.class) {return null;}// 先查询缓存Object cacheKey getCacheKey(method, targetClass);Object cached this.attributeCache.get(cacheKey);if (cached ! null) {if (cached NULL_TRANSACTION_ATTRIBUTE) {return null;}else {return (TransactionAttribute) cached;}}else {// 获取事务属性 TransactionAttribute txAttr computeTransactionAttribute(method, targetClass);// 事务属性不存在if (txAttr null) {this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);}else {String methodIdentification ClassUtils.getQualifiedMethodName(method, targetClass);if (txAttr instanceof DefaultTransactionAttribute) {((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);}if (logger.isDebugEnabled()) {logger.debug(Adding transactional method methodIdentification with attribute: txAttr);}// 将解析好的事务属性存入缓存this.attributeCache.put(cacheKey, txAttr);}return txAttr;} }2.3、computeTransactionAttribute computeTransactionAttribute方法会依次从方法上和类上查找事务申明使用的是findTransactionAttribute方法。 这里注意下第一行的内容只对public的方法可继续往下走这就解释了为什么事务只在public方法上生效。 protected TransactionAttribute computeTransactionAttribute(Method method, Class? targetClass) {if (allowPublicMethodsOnly() !Modifier.isPublic(method.getModifiers())) {return null;}Class? userClass ClassUtils.getUserClass(targetClass);// method为接口中的方法specificMethod为具体类中的方法Method specificMethod ClassUtils.getMostSpecificMethod(method, userClass);specificMethod BridgeMethodResolver.findBridgedMethod(specificMethod);// 查看方法中是否存在事务声明 TransactionAttribute txAttr findTransactionAttribute(specificMethod);if (txAttr ! null) {return txAttr;}// 查看方法所在类中是否存在事务声明 txAttr findTransactionAttribute(specificMethod.getDeclaringClass());if (txAttr ! null ClassUtils.isUserLevelMethod(method)) {return txAttr;}if (specificMethod ! method) {// 查看接口方法中是否存在事务声明txAttr findTransactionAttribute(method);if (txAttr ! null) {return txAttr;}// 查看接口类中是否存在事务声明txAttr findTransactionAttribute(method.getDeclaringClass());if (txAttr ! null ClassUtils.isUserLevelMethod(method)) {return txAttr;}}return null; }2.4、findTransactionAttribute findTransactionAttribute方法遍历所有的事务注解解析器判断哪一个能用来进行解析这里默认使用的是Spring的事务注解解析器SpringTransactionAnnotationParser。 protected TransactionAttribute findTransactionAttribute(Method method) {return determineTransactionAttribute(method); }protected TransactionAttribute findTransactionAttribute(Class? clazz) {return determineTransactionAttribute(clazz); }protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {if (ae.getAnnotations().length 0) {// 遍历事务注解解析器for (TransactionAnnotationParser annotationParser : this.annotationParsers) {// 解析事务注解TransactionAttribute attr annotationParser.parseTransactionAnnotation(ae);if (attr ! null) {return attr;}}}return null; } this.annotationParsers是在AnnotationTransactionAttributeSource类初始化的时候初始化的 public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {this.publicMethodsOnly publicMethodsOnly;this.annotationParsers new LinkedHashSetTransactionAnnotationParser(2);// 添加Spring事务注解解析器this.annotationParsers.add(new SpringTransactionAnnotationParser());// 添加JTA事务注解解析器if (jta12Present) { this.annotationParsers.add(new JtaTransactionAnnotationParser());}// 添加EJB事务注解解析器if (ejb3Present) {this.annotationParsers.add(new Ejb3TransactionAnnotationParser());} } 2.5、parseTransactionAnnotation annotationParser.parseTransactionAnnotation调用了SpringTransactionAnnotationParser的parseTransactionAnnotation方法内部又调用了parseTransactionAnnotation。 public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {AnnotationAttributes attributes AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);if (attributes ! null) {// 解析事务注解属性return parseTransactionAnnotation(attributes);}else {return null;} }parseTransactionAnnotation方法则解析了解析注解Transactional注解中声明的各种属性。 protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta new RuleBasedTransactionAttribute();Propagation propagation attributes.getEnum(propagation);rbta.setPropagationBehavior(propagation.value());Isolation isolation attributes.getEnum(isolation);rbta.setIsolationLevel(isolation.value());rbta.setTimeout(attributes.getNumber(timeout).intValue());rbta.setReadOnly(attributes.getBoolean(readOnly));rbta.setQualifier(attributes.getString(value));ArrayListRollbackRuleAttribute rollBackRules new ArrayListRollbackRuleAttribute();Class?[] rbf attributes.getClassArray(rollbackFor);for (Class? rbRule : rbf) {RollbackRuleAttribute rule new RollbackRuleAttribute(rbRule);rollBackRules.add(rule);}String[] rbfc attributes.getStringArray(rollbackForClassName);for (String rbRule : rbfc) {RollbackRuleAttribute rule new RollbackRuleAttribute(rbRule);rollBackRules.add(rule);}Class?[] nrbf attributes.getClassArray(noRollbackFor);for (Class? rbRule : nrbf) {NoRollbackRuleAttribute rule new NoRollbackRuleAttribute(rbRule);rollBackRules.add(rule);}String[] nrbfc attributes.getStringArray(noRollbackForClassName);for (String rbRule : nrbfc) {NoRollbackRuleAttribute rule new NoRollbackRuleAttribute(rbRule);rollBackRules.add(rule);}rbta.getRollbackRules().addAll(rollBackRules);return rbta; }到这里我们就找除了适配于当前Bean的增强结合之前AOP的内容整个步骤结束后会生成该Bean的代理类在方法执行时调用的事务的生效正是由代理类来完成的具体的事务控制我们将在下文讲解。 补充 事务仅对 public 方法有效 在本文内容的computeTransactionAttribute方法中第一行在读取注解上的属性方法中会优先判断方法是否是 public如果不是 public就不会读取事务配置信息。 因此Transactional注解只能在public方法上生效。
http://www.tj-hxxt.cn/news/130393.html

相关文章:

  • 大型网站架设需要考虑哪些问题淘宝怎么做引流和推广
  • 做网站电话说辞怎么买到精准客户的电话
  • 滁州做网站的公司微信分销系统有哪些平台
  • 机关网站建设和运行情况汇报电子商务网站建设的难点
  • 网站源码商城网站服务公司有哪些
  • 开题报告旅游网站开发3d建模需要什么学历
  • 决定网站打开的速度吗网站被做站公司贩卖
  • 甘肃机械化建设工程有限公司网站赣州章贡区哪里要招工
  • 网站收录大量下降一个网站建设的课程设计书
  • 招聘网站设计论文网站开发团队投入
  • 在线视频网站开发wordpress超链接颜色
  • 公司对比网站济南软件开发外包公司
  • wordpress 图片比例廊坊seo优化排名
  • 新手建立企业网站流程网站开发主管招聘
  • 手机做网站服务器吗建网站做外贸
  • 营销型企业网站建设方案松江专业做网站公司
  • 招聘网站制作公司wordpress如何关闭标签功能
  • 溧阳住房和城乡建设局网站微信看视频打赏网站建设
  • 做网站具体流程公司做的局域网网站怎么登陆
  • 怎样做网站关键词优化江苏建设监理协会官方网站
  • 基于asp.net网站开发做学校网站素材
  • html5 可以做网站吗刷外链工具
  • seo网站推广怎样wordpress主题seo模板
  • 深圳网站建设与制作公司网络推广方案案例
  • 自己做视频网站资源从哪里来wordpress公告栏插件
  • 网站建设行业发展史惠州网站建设制作价格
  • seo网站优化培训多少价格国家企业信用网官网
  • 网站页面组成部分外贸网站 流量
  • 安徽集团网站建设wordpress找回密码链接失效
  • 怎样制作一个自己的网站如何提升网站的收录量