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

Spring Cloud 学习 —— 简单了解

Spring Cloud 简介

官方文档:https://docs.spring.io/spring-cloud-release/reference/index.html

在学习 Spring Cloud 之前,先了解一下什么是分布式系统?

分布式系统

分布式系统是由多个独立计算机(节点)通过网络连接组成的系统,这些计算机协同工作,对用户表现为一个统一的整体。每个节点可以分布在不同的地理位置,通过消息传递(如 HTTP、RPC)完成通信,共同完成一个任务。其核心特征包括:

  • 资源共享:整合分散的资源(计算、存储、服务)。
  • 高可用性:通过冗余避免单点故障。
  • 可扩展性:通过水平扩展(增加节点)提升系统性能。
  • 透明性:用户无需感知系统内部的分布性(如访问一个网站时,用户不知道背后有多少服务器)。

这样分布式系统具有很大的容错优势。

分布式系统的作用

核心作用技术实现示例
服务解耦微服务拆分
配置统一管理动态配置中心
流量控制熔断降级机制
服务发现注册中心动态路由

分布式系统的痛点

  1. 服务发现与治理:分布式系统中节点动态变化(如扩容、宕机)会导致服务定位困难。
  2. 服务间通信优化:跨服务调用需处理序列化、负载均衡等问题。
  3. API 网关与流量控制:网络不可靠性可能导致请求堆积或服务过载。
  4. 熔断与故障恢复:服务雪崩效应是分布式系统的常见风险。
  5. 分布式事务管理:跨服务事务一致性是核心挑战。
  6. 统一配置管理:多节点配置分散会增加运维复杂度。
  7. 分布式链路追踪:请求可能经过多个服务(如用户请求 → 订单服务 → 支付服务 → 库存服务),如何追踪完整链路?

Spring Cloud 是什么

为了解决分布式系统的痛点,Spring Cloud 应运而生。

Spring Cloud 是一个基于 Spring Boot 的微服务架构开发工具集,提供了一系列组件和框架,用于简化分布式系统的构建、部署和治理。它整合了 Netflix、Alibaba 等开源生态的成熟解决方案(如 Eureka、Sentinel、Nacos),帮助开发者快速实现服务发现、负载均衡、熔断降级等分布式系统核心功能。

核心定位

  • 微服务全家桶:提供微服务架构中常见问题的标准化解决方案。
  • 开箱即用:基于 Spring Boot 的约定优于配置原则,简化开发。
  • 模块化设计:按需引入组件(如仅需服务发现时引入 spring-cloud-starter-netflix-eureka-client)。

Spring Cloud 解决的核心问题

分布式系统痛点Spring Cloud 解决方案核心组件
服务发现与注册动态管理服务实例的地址和状态Consul、Nacos
服务间通信简化 HTTP/RPC 调用,处理负载均衡和容错LoadBalancer、OpenFeign
配置管理集中管理分布式配置,支持动态刷新Consul、Nacos
熔断与降级防止服务雪崩,提供故障隔离和降级逻辑Resilience4j、Sentinel
API 网关统一入口,处理路由、鉴权、限流等跨横切面关注点Gateway
分布式追踪追踪请求链路,定位性能瓶颈Micrometer、Zipkin
分布式事务解决跨服务数据一致性问题Seata

Spring Cloud 与 Spring Cloud Alibaba 关系

Spring Cloud Alibaba 是 阿里巴巴 开源的 Spring Cloud 子项目,属于 Spring Cloud 生态的一部分。它在 Spring Cloud 标准组件的基础上,替换或增强了部分功能,并深度集成了阿里云的中间件(如 Nacos、Sentinel、RocketMQ)。

组件生态差异

功能Spring CloudSpring Cloud Alibaba
服务注册中心、配置中心ConsulNacos
熔断限流Resilience4jSentinel
分布式事务无原生支持(依赖第三方)Seata(AT/TCC 模式)
消息中间件无原生支持RocketMQ(阿里自研)

Consul 服务注册与发现、配置管理

官网:https://www.consul.io/

github 地址:https://github.com/hashicorp/consul

Spring Cloud Consul github 地址:https://github.com/spring-cloud/spring-cloud-consul

Spring Cloud Consul 文档:https://docs.spring.io/spring-cloud-consul/reference/

什么是 Consul

Consul 是由 HashiCorp 公司推出的开源分布式工具,专为微服务架构设计,提供服务发现配置管理健康检查多数据中心支持等核心功能。其架构基于分布式共识算法(Raft),具备高可用性和横向扩展能力。

核心功能

  1. 服务发现
    • 服务注册:服务提供者(如 API 或 MySQL)通过 Consul 客户端将自身信息(IP、端口、元数据)注册到 Consul 集群。
    • 服务查询:消费者通过 DNS 或 HTTP 接口查询服务列表,动态获取可用服务节点。
    • 健康检查
      • 支持对服务进行主动探测(如 HTTP 状态码检查)或被动上报
      • 自动剔除不健康节点,避免流量路由到故障服务。
  2. 配置管理
    • 键值存储
      • 支持动态配置存储,如功能开关、数据库连接字符串等。
      • 通过 HTTP API 或 Consul 模板(Consul-Template)实现配置动态加载。
    • 多环境支持
      • 通过命名空间或路径区分不同环境(开发/生产)的配置。
      • 例如:config/dev/dbconfig/prod/db 存储不同环境的数据库配置。
  3. 多数据中心支持
    • 可跨多个地理区域部署 Consul 集群,实现全局服务发现跨数据中心配置同步
    • 通过 WAN 网络连接不同数据中心,支持灾备和流量调度。
  4. 安全特性
    • 访问控制(ACL):限制客户端对服务或配置的读写权限。
    • 通信加密:支持 TLS 加密服务间通信,确保数据传输安全。
  5. 服务网格(Service Mesh)
    • 集成 Connect 功能,提供基于 mTLS 的服务间身份认证和流量加密。
    • 支持细粒度流量策略(如路由规则、熔断策略)。

安装与启动

下载地址:https://developer.hashicorp.com/consul/install

Mac 安装时,需要配置环境变量。

验证是否安装成功:consul version

启动 consul:consul agent -dev

启动完成后访问:http://localhost:8500/

出现以下页面配置成功。

在这里插入图片描述

启动命令详解

核心命令结构
consul agent 参数
关键运行模式
参数作用适用场景
-dev启动开发模式(单节点)本地测试
-server启动服务端模式生产集群
-client指定客户端节点集群客户端
常用参数说明
参数示例说明
-data-dir-data-dir=/tmp/consul数据存储目录(默认:/consul/data
-config-dir-config-dir=/etc/consul.d配置文件目录(支持 .json/.hcl
-bind-bind=0.0.0.0绑定监听地址
-http-port-http-port=8501修改 Web UI 端口(默认 8500)
-node-node=web-server-1自定义节点名称
-datacenter-datacenter=dc2指定数据中心名称
启动示例
  • 开发模式(快速测试):

    consul agent -dev -http-port=8501          
    

    输出包含 Consul agent running! 即启动成功。

  • 生产模式(集群部署):

    consul agent -server -bootstrap-expect=3 -data-dir=/var/consul -node=server-1 -bind=192.168.1.10
    

    参数说明

    • -bootstrap-expect=3:预期集群有 3 个服务端节点。
    • -bind:绑定本机 IP。

Consul 服务注册代码示例

  1. 父工程导入依赖:

    <dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2024.0.1</version><type>pom</type><scope>import</scope></dependency></dependencies>
    </dependencyManagement>
    

    版本取决于 Spring Boot 的版本。

  2. 创建服务提供者:

    1. 导入依赖:

      <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>
      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      
    2. 配置文件:

      spring:application:name: service-producercloud:consul:host: localhostport: 8500discovery:health-check-path: /actuator/healthhealth-check-interval: 15s
      
    3. 主启动类:

      @SpringBootApplication
      @EnableDiscoveryClient // 启用服务注册与发现
      public class ProducerApplication {public static void main(String[] args) {SpringApplication.run(ProducerApplication.class, args);}
      }
      
    4. 接口:

      @RestController
      @RequestMapping("/api")
      public class ProducerController {@GetMapping("/hello")public String hello() {return "Hello from Producer Service!";}
      }
      
  3. 创建服务消费者:

    1. 配置文件:

      server:port: 8088
      spring:application:name: service-consumercloud:consul:host: localhostport: 8500
      
    2. 通过 OpenFeign 调用服务:

      1. 导入依赖:

        <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        
      2. 主启动类:

        @EnableFeignClients
        @SpringBootApplication
        public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class, args);}
        }
        
      3. 定义 Feign 接口:

        @FeignClient(name = "service-producer")
        public interface ProducerClient {@GetMapping("/api/hello")String hello();
        }
        
      4. controller 层:

        @RestController
        @RequestMapping("/feign-consumer")
        public class FeignConsumerController {@Autowiredprivate ProducerClient producerClient;@GetMapping("/call")public String call() {return producerClient.hello();}
        }
        

编写完成后,先运行服务提供者代码,查看 consul 是否成功注册服务:

在这里插入图片描述

成功注册后,运行服务消费者代码,访问 http://localhost:8088/feign-consumer/call。

返回 Hello from Producer Service! 代表成功。

Consul 配置中心代码示例

在 consul 管理页面配置信息,以 yaml 格式为例,首先创建 config 目录(官方推荐):

在这里插入图片描述

在 config 目录下再创建一个或多个目录(通常为微服务名字 + 不同环境,例如 order-service-dev

在这里插入图片描述

在对应环境的目录下配置信息,key 需要自己设定,value 就是 yaml 格式的配置信息。

在这里插入图片描述

配置完成后编写代码:

  1. 导入依赖:

    <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-config</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>
    </dependencies>
    
  2. 主配置类:

    package com.yigongsui;import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
    @SpringBootApplication
    public class Order {public static void main(String[] args) {SpringApplication.run(Order.class, args);}
    }
    
  3. 编写配置文件 bootstrap.yml ,官方推荐:

    server:port: 8888
    spring:application:name: order-servicecloud:consul:host: localhostport: 8500discovery:service-name: ${spring.application.name}config:# 前缀,推荐为 configprefix: config# 服务名字default-context: order-serviceformat: yaml# 环境分隔符,如果为dev环境,匹配的就是order-service-dev目录profile-separator: '-'# key 的名字data-key: orderServicewatch:enabled: true              # 动态配置更新监听[^1]delay: 1000                # 监听间隔(毫秒)fail-fast: true              # 启动时若无法连接 Consul 则报错
    
  4. controller 层:

    package com.yigongsui.controller;import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;@RestController
    @RefreshScope
    public class OrderController {@Value("${mysql.root}")private String root;@Value("${mysql.password}")private String password;@GetMapping("/hello")public String hello(){return root + password;}}
    

运行成功,访问:http://localhost:8888/hello

LoadBalancer 服务调用和负载均衡

Spring Cloud Balancer 官方文档:https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html

什么是 LoadBalancer

LoadBalancer 是 Spring Cloud 生态中的客户端负载均衡组件,主要解决微服务架构中服务实例的动态选择问题。其核心功能包括:

  1. 服务实例选择

    根据注册中心(如 Nacos、Consul)获取服务实例列表,自动选择目标实例。

  2. 负载均衡策略

    提供轮询、随机等算法,支持自定义策略。

  3. 与 Spring Cloud 组件深度集成

    无缝支持 RestTemplateWebClientOpenFeign 的负载均衡调用。

解决的问题

问题类型LoadBalancer 的解决方案
客户端负载均衡替代 Netflix Ribbon,提供轻量级、高性能的负载均衡实现
服务发现集成通过 @LoadBalanced 注解自动注入服务发现能力,避免硬编码地址
策略扩展性支持自定义负载均衡算法(如权重分配、区域优先)
依赖维护规避 Ribbon 的维护停滞风险,紧跟 Spring 生态更新

核心功能

  1. 注解驱动

    通过 @LoadBalanced 注解快速启用负载均衡:

    @Bean
    @LoadBalanced  // 启用负载均衡
    public RestTemplate restTemplate() {return new RestTemplate();
    }
    

    (自动将普通 HTTP 请求转换为负载均衡调用)

  2. 策略配置

    • 默认策略:轮询(RoundRobinLoadBalancer
    • 自定义策略:继承 ReactorServiceInstanceLoadBalancer 接口实现:
    public class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {// 实现权重选择逻辑
    }
    

    (通过 @LoadBalancerClient 注解指定策略)

  3. 健康检查

    自动过滤不可用实例,结合 HealthCheck 机制提升调用可靠性。

OpenFeign 服务接口调用

github 地址:https://github.com/spring-cloud/spring-cloud-openfeign

官方文档:https://docs.spring.io/spring-cloud-openfeign/reference/

什么是 OpenFeign

OpenFeign 是一个声明式的 HTTP 客户端框架,属于 Spring Cloud 生态中的服务调用组件。它通过定义接口和注解的方式,将 HTTP 请求抽象为本地方法调用,开发者无需手动处理底层网络通信细节。其核心设计目标是简化服务间通信,提升微服务架构下的开发效率。

核心功能

  1. 声明式HTTP客户端

    OpenFeign 通过接口 + 注解定义 HTTP 请求,开发者无需手动处理底层 HTTP 通信,例如:

    @FeignClient(name = "product-service")
    public interface ProductApi {@GetMapping("/products/{id}")Product getById(@PathVariable("id") Long id);
    }
    

    动态代理会自动生成实现类,向 http://product-service/products/{id} 发送 GET 请求。

  2. 负载均衡集成

    默认集成 Ribbon 实现客户端负载均衡,请求会自动分配到不同服务实例。配置示例:

    ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
    
  3. 熔断降级支持

    可与 Sentinel 集成实现服务熔断。配置示例:

    feign:sentinel:enabled: true
    

代码实现关键步骤

  1. Maven 依赖:

    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. 超时控制

    feign:client:config:default:connectTimeout: 2000  # 连接超时readTimeout: 5000     # 读取超时
    
  3. 重试机制

    默认不启用重试,需自定义 Retryer:

    public class CustomRetryer extends Retryer.Default {public CustomRetryer() {super(100, 1000, 3);  // 间隔100ms,最大间隔1s,重试3次}
    }
    

Circuit Breaker 断路器

github:https://github.com/spring-cloud/spring-cloud-circuitbreaker

官方文档:https://docs.spring.io/spring-cloud-circuitbreaker/reference/

什么是 Circuit Breaker

Circuit Breaker 是一种容错设计模式,灵感来源于电路中的熔断器。其核心目标是隔离故障服务,防止级联故障扩散到整个系统。当服务调用频繁失败时,断路器会主动“熔断”,暂时阻止后续请求,并给予下游服务恢复时间。

核心状态

  1. Closed(闭合状态)
    • 默认状态,所有请求正常通过。
    • 持续监控失败率。
    • 触发熔断条件:失败率超过阈值(例如 50%)或超时请求过多。
  2. Open(开放状态)
    • 所有请求直接返回失败(快速失败)。
    • 持续时间由 waitDurationInOpenState 参数控制(例如5秒)。
    • 进入半开状态的过渡阶段。
  3. Half-Open(半开状态)
    • 允许有限数量的“探针请求”通过(通过 permittedNumberOfCallsInHalfOpenState 配置)。
    • 若探针请求成功率达标则恢复 Closed 状态,否则重回 Open 状态

工作流程

[Closed] → (失败率超标) → [Open] ↑          ↓ (等待时间结束)← [Half-Open] → (探针成功)→ [Closed](探针失败)↗

Resilience4j 服务熔断与降级

Resilience4j 是 Spring Cloud Circuit Breaker 的官方推荐实现之一,专注于通过函数式编程实现轻量级容错控制。提供断路器、限流器等六大核心功能模块。

核心模块

  1. 断路器(Circuit Breaker):自动熔断异常服务。
  2. 限流器(Rate Limiter):控制请求速率,防止服务过载。
  3. 隔离机制(Bulkhead):通过线程池/信号量隔离资源。
  4. 重试策略(Retry):智能重试失败请求。
  5. 超时控制(Time Limiter):防止长时间阻塞。
  6. 结果缓存(Cache):减少重复计算。

与 Spring Cloud 集成

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
  • 注解驱动开发:通过 @CircuitBreaker 等注解快速实现容错逻辑。
  • 配置中心对接:支持通过 application.yml 动态调整参数。
  • Feign 集成:与声明式 HTTP 客户端无缝协作实现服务限流。

核心功能实现示例

  1. 断路器配置
resilience4j.circuitbreaker:instances:backendA:failureRateThreshold: 50waitDurationInOpenState: 5sringBufferSizeInClosedState: 100
  1. 限流器使用
@RateLimiter(name = "apiLimiter", fallbackMethod = "rateLimitFallback")
public ResponseEntity<String> apiEndpoint() {// 业务逻辑
}

Micrometer 分布式链路追踪

github:https://github.com/micrometer-metrics/micrometer

官方文档:https://docs.micrometer.io/micrometer/reference/

什么是 Micrometer

Micrometer 是一个面向 JVM 应用的度量指标门面库(Metrics Facade),类似于日志领域的 SLF4J。它提供统一的 API 规范,允许开发者以供应商中立的方式记录应用指标,并支持将数据输出到多种监控系统(如 Prometheus、Datadog、InfluxDB 等)。

核心特性

  1. 统一度量接口
  • 支持 12+ 种监控系统,包括:

    Prometheus | Datadog | InfluxDB | Graphite | New Relic
    
  • 通过简单配置切换监控后端,无需修改业务代码。

  1. 标签化维度分析(Tags)
  • 使用键值对组合标识指标,增强数据分析能力:

    // 统计不同支付方式的成功率
    Counter.builder("payment.count").tag("method", "alipay") .tag("status", "success").register(registry).increment();
    
  • 相比传统监控工具(如 dropwizard-metrics)的扁平化指标命名,支持多维度交叉分析。

  1. 丰富的度量类型
类型功能描述
Counter累加型指标(如请求总数)
Timer耗时统计(如接口响应时间)
Gauge瞬时值测量(如内存使用量)
Distribution数据分布统计(如分位数计算)
  1. 与 Spring Boot 深度集成
  • 通过 Actuator 暴露指标端点:

    # application.yml
    management:endpoints:web:exposure:include: health,metrics,prometheusmetrics:export:prometheus:enabled: true
    
  • 访问 /actuator/prometheus 可直接获取 Prometheus 格式指标。

  1. 内存安全机制
  • Gauge 类指标采用弱引用策略,避免因对象未及时释放导致内存泄漏:

    Gauge.builder("cache.size", cache, Cache::size).strongReference(false) // 默认弱引用.register(registry);
    
  • 自动处理被垃圾回收的对象,防止报告 NaN 或无效数据。

Gateway 服务网关

github:https://github.com/spring-cloud/spring-cloud-gateway

官方文档:https://docs.spring.io/spring-cloud-gateway/reference/

什么是 Gateway

Spring Cloud Gateway 是 Spring Cloud 生态中基于响应式编程模型的 API 网关,其核心作用可概括为:

流量管控中心 + 安全防护屏障 + 服务治理节点流量管控中心 + 安全防护屏障 + 服务治理节点

在微服务架构中,它处于客户端与后端服务之间,处理所有请求的路由、过滤和转换。

架构原理

  1. 核心组件

    • 路由(Route):定义请求转发规则,包含目标 URI、断言和过滤器链。
    • 断言(Predicate):基于请求参数(路径、Header、时间等)的匹配条件。
    • 过滤器(Filter):修改请求/响应的处理逻辑,分为全局过滤器和路由过滤器。
  2. 处理流程

    客户端请求 → 路由匹配 → 执行前置过滤器 → 转发到后端服务 → 执行后置过滤器 → 返回响应          
    
  3. 数学模型示例(限流算法): 使用令牌桶算法实现限流时,设桶容量为 b,令牌生成速率为 r,则允许的最大突发请求量为:

    突发流量 = b + r × t

    当请求速率 λ > r 时触发限流。

关键特性与作用

功能模块实现方式典型场景示例
动态路由结合注册中心(如 Nacos)实现服务发现灰度发布、AB 测试
限流熔断集成 Resilience4j 或 Sentinel 组件秒杀活动流量控制
安全认证通过 JWT 验证过滤器实现OAuth2 鉴权
协议转换WebSocket 与 HTTP 协议互转实时通信服务代理
监控日志集成 Micrometer 输出指标到 Prometheus实时流量监控1

简单应用示例

  1. 路由配置(YAML)
spring:cloud:gateway:routes:- id: order_serviceuri: lb://order-servicepredicates:- Path=/api/orders/**filters:- StripPrefix=2- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 100 # 每秒令牌数redis-rate-limiter.burstCapacity: 200 # 桶容量
  1. 自定义全局过滤器
@Component
public class AuthFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String token = exchange.getRequest().getHeaders().getFirst("Authorization");if (!validateToken(token)) {exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);return exchange.getResponse().setComplete();}return chain.filter(exchange);}
}

相关文章:

  • ⼤模型驱动的DeepInsight Copilot在蚂蚁的技术实践
  • Express教程【002】:Express监听GET和POST请求
  • 两阶段uplift建模(因果估计+预算分配)的讲座与自己动手实践(一)
  • 血糖监测仪解决方案推荐芯片-NRF52832/HS6621/OM6626
  • Windows 11 家庭版 安装Docker教程
  • RCU stall 异常卡住问题
  • 【C/C++】cmake实现Release版本禁用调试接口技巧
  • YOLOv8分割onnx实战及tensorRT部署
  • Java 之殇:从中流砥柱到“被温柔替代”
  • 大话软工笔记—分离之业务与管理
  • 深度学习实战110-基于深度学习的工业系统故障诊断技术研究(卷积网络+注意力机制模型)
  • 核心机制:确认应答和超时重传
  • 【leetcode】02.07. 链表相交
  • 什么是AI Agent?大白话新手教学
  • Python基本运算符
  • Java异常与错误:核心区别深度解析
  • Baklib内容中台AI赋能智能服务升级
  • 【论文阅读】DanceGRPO: Unleashing GRPO on Visual Generation
  • 基于VU37P的高性能采集板卡
  • Vue3中Element-Plus中el-input及el-select 边框样式
  • 跨境独立站怎么运营/百度爱采购平台官网
  • 网站权重转移做排名/绍兴网站快速排名优化
  • 大数据平台的搭建/seo刷点击软件
  • 棋牌软件定制开发/上海网站排名seo公司哪家好
  • 企业服务建设网站/如何做网站推广的策略
  • 网站备案文件下载/吴江网站制作