【愚公系列】2023年11月 Java教学课程 195

编程入门 行业动态 更新时间:2024-10-21 06:40:26

【<a href=https://www.elefans.com/category/jswz/34/1769546.html style=愚公系列】2023年11月 Java教学课程 195"/>

【愚公系列】2023年11月 Java教学课程 195

🏆 作者简介,愚公搬代码
🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,51CTO博客专家等。
🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏

文章目录

  • 🚀前言
  • 🚀一、Spring Cloud Config分布式配置组件
    • 🔎1.简介
    • 🔎2.工作原理
    • 🔎3.Spring Cloud Config 的特点
    • 🔎4.搭建 Config 服务端
      • 🦋1.1 配置文件说明
    • 🔎5.搭建 Config 客户端
    • 🔎6.Config 客户端刷新
      • 🦋1.1 问题演示
      • 🦋1.2 手动配置刷新
      • 🦋1.3 自动配置刷新
        • ☀️1.3.1 Spring Cloud Bus 的基本原理
        • ☀️1.3.2 Spring Cloud Bus 的基本原理
        • ☀️1.3.3 Spring Cloud Bus 动态刷新配置(全局广播)
          • 🌈1.3.3.1 服务端配置
          • 🌈1.3.3.2 客户端配置
        • ☀️1.3.4 Spring Cloud Bus 动态刷新配置(定点通知)
  • 🚀感谢:给读者的一封信


🚀前言

在微服务架构中,每个服务都需要一些配置信息,例如数据库连接、日志级别、端口号等等。这些配置信息通常存储在配置文件中,但是在分布式的环境下,如何管理和更新这些配置文件呢?

一种解决方案是使用分布式配置文件。分布式配置文件是一种可以在多个应用程序之间共享的配置文件。这些文件通常存储在配置中心,例如 ZooKeeper、Consul、etcd 等等。

使用分布式配置文件的优点包括:

  1. 集中管理:所有的配置信息都存储在配置中心中,管理员可以方便地对其进行修改和更新。

  2. 实时生效:当配置文件发生改变时,配置中心会自动通知所有使用该配置文件的应用程序,从而实现实时更新配置信息的目的。

  3. 灵活性:不同的服务可以共享同一个配置文件,也可以使用不同的配置文件,这种灵活性使得服务可以根据自己的需要进行配置。

使用分布式配置文件需要注意以下几点:

  1. 安全性:配置信息可能包含敏感信息,如密码、密钥等等,所以必须采取一些措施来保证其安全性。

  2. 可靠性:配置中心需要保证高可用性,从而避免配置文件不可用的情况。

  3. 并发问题:当多个应用程序同时更新同一个配置文件时,会出现并发问题,需要采取一些措施来避免这种情况的发生。

最后,需要注意的是,使用分布式配置文件虽然可以方便地管理和更新配置信息,但也会带来一些额外的复杂性。因此,在使用分布式配置文件时,需要权衡其优缺点,并根据实际情况做出决策。

🚀一、Spring Cloud Config分布式配置组件

🔎1.简介

Spring Cloud Config是由Spring Cloud团队开发的项目,旨在为微服务架构中的各个微服务提供集中化的外部配置支持。它的核心思想是将各个微服务的配置文件集中存储在一个外部的存储仓库或系统中,例如Git或SVN,以实现对配置的统一管理和支持微服务的运行。

Spring Cloud Config由两个主要组件组成:

  1. Config Server(配置服务器):作为分布式配置中心,是一个独立运行的微服务应用。它连接配置仓库,并为客户端提供获取配置信息、加密和解密信息的访问接口。
  2. Config Client(配置客户端):指的是微服务架构中的各个微服务。它们通过Config Server来管理配置,并从Config Server中获取和加载配置信息。

Spring Cloud Config默认使用Git作为配置信息的存储方式,因此可以天然地支持对微服务配置的版本管理。通过使用Git客户端工具,我们可以方便地管理和访问配置内容。除了Git,Spring Cloud Config还提供了对其他存储方式的支持,例如SVN、本地化文件系统等。

Spring Cloud Config为微服务架构中的配置管理提供了便利和灵活性,使得配置的集中化管理成为可能。

🔎2.工作原理

Spring Cloud Config的工作原理如下:

  1. Config Server启动:首先,Config Server作为一个独立的微服务应用启动。它会连接配置仓库(如Git、SVN等)来获取配置信息。

  2. 配置仓库存储配置文件:配置文件可以存储在Git、SVN等版本控制系统中,也可以存储在本地化文件系统中。Config Server会根据配置文件的路径和命名规则来组织和管理配置信息。

  3. Config Client请求配置:当Config Client启动时,它会向Config Server发送请求,请求所需的配置信息。请求可以包括应用名称、环境等参数。

  4. Config Server响应配置:Config Server接收到Config Client的请求后,会根据请求的参数从配置仓库中获取相应的配置信息。然后,它将配置信息以HTTP或其他协议的形式返回给Config Client。

  5. Config Client加载配置:Config Client接收到Config Server返回的配置信息后,会将配置信息加载到应用程序中。应用程序可以根据需要使用这些配置信息来进行相应的配置。

  6. 定时刷新配置:Config Client可以定时向Config Server发送请求,以获取最新的配置信息。这样,当配置发生变化时,Config Client可以及时更新配置,而无需重启应用程序。

Spring Cloud Config通过Config Server和Config Client之间的交互,实现了配置信息的集中管理和动态更新。Config Server负责从配置仓库中获取配置信息,并提供访问接口给Config Client。Config Client则负责加载配置信息,并在需要时向Config Server请求最新的配置。这种架构使得微服务的配置管理变得简单和灵活。

🔎3.Spring Cloud Config 的特点

Spring Cloud Config具有以下特点:

  1. 集中化配置管理:Spring Cloud Config提供了一个分布式配置中心,可以将各个微服务的配置文件集中存储在一个外部的存储仓库或系统中。这样,可以方便地对配置进行统一管理,而不需要在每个微服务中维护独立的配置文件。

  2. 外部化配置:通过将配置文件存储在外部的存储仓库或系统中,可以实现配置的外部化。这意味着配置可以在不重新部署应用程序的情况下进行修改和更新,从而提供了更高的灵活性和可维护性。

  3. 动态配置更新:Spring Cloud Config支持配置的动态更新。当配置发生变化时,Config Client可以通过定时刷新或手动触发的方式向Config Server请求最新的配置信息,从而实现配置的实时更新,而无需重启应用程序。

  4. 版本管理:Spring Cloud Config默认使用Git作为配置信息的存储方式,因此天然支持对配置的版本管理。通过Git客户端工具,可以方便地管理和访问配置内容的历史版本。

  5. 多环境支持:Spring Cloud Config支持多环境的配置管理。可以为不同的环境(如开发、测试、生产)创建不同的配置文件,并通过配置文件的命名规则和环境参数来区分不同的配置。

  6. 安全性支持:Spring Cloud Config提供了对配置信息的加密和解密支持,以保护敏感信息的安全性。可以使用加密算法对配置信息进行加密,并在需要时进行解密,以防止配置信息的泄露。

Spring Cloud Config提供了一种方便、灵活和安全的方式来管理和更新微服务的配置信息。它的特点包括集中化配置管理、外部化配置、动态配置更新、版本管理、多环境支持和安全性支持。这些特点使得Spring Cloud Config成为构建可扩展和可维护的微服务架构的重要组成部分。

🔎4.搭建 Config 服务端

1、使用gitee创建远程仓库,上传配置文件

新建一个名为 config-dev.yml 的文件,并将其上传到 springcloud-config 仓库 master 分支下

config-dev.yml 的内容如下。
config:info: c.bianchengversion: 1.0

2、搭建 config server 模块

模块搭建就不写了

3、导入 config-server 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0" xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><artifactId>spring-cloud-demo2</artifactId><groupId>net.biancheng.c</groupId><version>0.0.1-SNAPSHOT</version></parent><groupId>net.biancheng.c</groupId><artifactId>micro-service-cloud-config-center-3344</artifactId><version>0.0.1-SNAPSHOT</version><name>micro-service-cloud-config-center-3344</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--配置中心服务器依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

4、编写配置,设置 gitee 远程仓库地址

server:port: 3344 #端口号
spring:application:name: spring-cloud-config-center #服务名cloud:config:server:git:# Git 地址,.git# 码云(gitee)地址 uri: .git  (github 站点访问较慢,因此这里我们使用 gitee)uri: .git#仓库名search-paths:- springcloud-configforce-pull: true# 如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写# username: ********# password: ********#分支名label: mastereureka:                                            client: #将客户端注册到 eureka 服务列表内service-url: defaultZone: :7001/eureka/,:7002/eureka/,:7003/eureka/  #将服务注册到 Eureka 集群

5、测试访问远程配置文件

package net.biancheng.c;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloudflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class MicroServiceCloudConfigCenter3344Application {public static void main(String[] args) {SpringApplication.run(MicroServiceCloudConfigCenter3344Application.class, args);}
}

6、访问配置文件

http://localhost:3344/master/config-dev.yml


7、在浏览器上访问“http://localhost:3344/config/dev/master”

{"name":"config","profiles":["dev"],"label":"master","version":"9caafcc3498e04147463482f8b29e925e8afcc3a","state":null,"propertySources":[{"name":".git/config-dev.yml","source":{"config.info":"c.biancheng","config.version":1.0}}]}

🦋1.1 配置文件说明

Spring Cloud Config 规定了一些默认的配置文件访问规则,可以将配置文件存储在版本控制系统(如 Git)中,然后通过 Spring Cloud Config Server 进行访问。访问规则如下:

  1. 首先需要指定配置文件的名称和环境,例如:application.ymldev

  2. 然后需要指定 Spring Cloud Config Server 的访问路径和端口号(默认为 8888)。

  3. 最后需要指定 Git 仓库的地址和分支(默认为 master)。

例如,如果要访问名称为 application.yml、环境为 dev 的配置文件,可以使用以下 URL:http://localhost:8888/application-dev.yml。其中,localhost 表示 Spring Cloud Config Server 的地址,8888 表示端口号,application-dev.yml 表示配置文件的名称和环境。

注意,以上是 Spring Cloud Config 的默认访问规则,也可以根据实际需求进行自定义。

🔎5.搭建 Config 客户端

1、导入 starter-config 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0" xmlns:xsi=""xsi:schemaLocation=".0.0 .0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><artifactId>spring-cloud-demo2</artifactId><groupId>net.biancheng.c</groupId><version>0.0.1-SNAPSHOT</version></parent><groupId>net.biancheng.c</groupId><artifactId>micro-service-cloud-config-client-3355</artifactId><version>0.0.1-SNAPSHOT</version><name>micro-service-cloud-config-client-3355</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Spring Cloud Config 客户端依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

2、配置config server 地址,读取配置文件名称等信息

#bootstrap.yml 是系统级别的,加载优先级高于 application.yml ,负责从外部加载配置并解析
server:port: 3355 #端口号
spring:application:name: spring-cloud-config-client #服务名cloud:config:label: master #分支名称name: config  #配置文件名称,config-dev.yml 中的 configprofile: dev  #环境名  config-dev.yml 中的 dev#这里不要忘记添加 http:// 否则无法读取uri: http://localhost:3344 #Spring Cloud Config 服务端(配置中心)地址
eureka:client: #将客户端注册到 eureka 服务列表内service-url:defaultZone: :7001/eureka/,:7002/eureka/,:7003/eureka/  #将服务注册到 Eureka 集群

3、获取配置值

启动类

package net.biancheng.c;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloudflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class MicroServiceCloudConfigClient3355Application {public static void main(String[] args) {SpringApplication.run(MicroServiceCloudConfigClient3355Application.class, args);}
}

读取文件

package net.biancheng.c.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//读取配置中心指定配置文件的内容,并展示到页面
@RestController
public class ConfigClientController {@Value("${server.port}")private String serverPort;@Value("${config.info}")private String configInfo;@Value("${config.version}")private String configVersion;@GetMapping(value = "/getConfig")public String getConfig() {return "info:" + configInfo + "<br/>version:" + configVersion + "<br/>port:" + serverPort;}
}

4、启动测试

使用浏览器访问:http://localhost:3355/getConfig

🔎6.Config 客户端刷新

🦋1.1 问题演示

1、将配置文件 config-dev.yml 中 config.version 的值修改为 2.0

config:info: c.bianchengversion: 2.0

2、访问服务端

3、访问客户端


重启客户端再次访问

通过该实例,我们可以得到以下 2 点结论,

  • 配置更新后,Spring Cloud Config 服务端(Server)可以直接从 Git 仓库中获取最新的配置。

  • 除非重启 Spring Cloud Config 客户端(Client),否则无法通过 Spring Cloud Config 服务端获取最新的配置信息。

🦋1.2 手动配置刷新

1、在客户端添加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、bootstrap.yml 中添加以下配置

# Spring Boot 2.50对 actuator 监控屏蔽了大多数的节点,只暴露了 health 节点,本段配置(*)就是为了开启所有的节点
management:endpoints:web:exposure:include: "*"   # * 在yaml 文件属于关键字,所以需要加引号

3、使用 @RefreshScope 注解开启配置刷新

package net.biancheng.c.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;// 读取配置中心指定配置文件的内容,并展示到页面
@RefreshScope //为了让动态(手动)的获取最新的git 配置,在添加 actuator 监控加载 RefreshScope,
@RestController
public class ConfigClientController {@Value("${server.port}")private String serverPort;@Value("${config.info}")private String configInfo;@Value("${config.version}")private String configVersion;@GetMapping(value = "/getConfig")public String getConfig() {return "info:" + configInfo + "<br/> version:" + configVersion + "<br/>port:" + serverPort;}
}

4、修改git上配置文件

config:info: c.bianchengversion: 3.0

5、执行命令

添加配置

management.endpoints.web.exposure.include: refresh

使用curl工具发送post请求

curl -X POST http://localhost:3355/actuator/refresh 

6、再次访问

7、问题点


就是需要仓库发生变化,每个客户端都需要执行命令不太现实。

🦋1.3 自动配置刷新

Config+Bus 可以实现配置的动态刷新

☀️1.3.1 Spring Cloud Bus 的基本原理

Spring Cloud Bus(简称 Bus)利用消息队列来传播分布式系统中的状态变化事件,以实现微服务系统的自动刷新。其基本原理如下:

  1. 组件间的变化事件(如配置变更、路由变更等)被发布到消息队列中,消息格式为 JSON。
  2. 所有订阅该消息队列的组件都会接收到该消息,并根据消息中携带的信息来更新自己的状态。
  3. 当一个组件的状态发生变化时,该组件再次发布变化事件到消息队列中,以实现状态变化的传播。

Bus 可以使用多种消息中间件来实现消息传播,如 RabbitMQ、Kafka 等。同时,它还支持 Spring Cloud Config 和 Spring Cloud Stream 等组件进行集成,可以轻松实现微服务系统的配置管理和消息传递。

☀️1.3.2 Spring Cloud Bus 的基本原理

Spring Cloud Bus 是一种基于消息代理的轻量级分布式系统的通信框架。它利用消息代理的能力,将分布式系统中的各个节点连接起来,通过消息传递的方式,实现了配置自动更新,事件广播以及其他分布式系统所需的功能。

Spring Cloud Bus 在实现动态刷新配置的过程中,主要的原理可以分为以下步骤:

  1. 将所有需要自动更新配置的服务节点连接到消息代理(例如 RabbitMQ、Kafka 等),并订阅相应的主题(Topic)。

  2. 当某个服务的配置发生变化时,Spring Cloud Bus 会将这个变化事件发送到消息代理上。

  3. 订阅了相应主题的其他服务节点收到这个事件,然后触发本地配置的更新。

  4. 当服务节点更新完配置后,也可以通过 Spring Cloud Bus 将配置更新事件广播到其他服务节点。

  5. 所有服务节点都通过上述方式实现了配置的自动更新。

Spring Cloud Bus 主要通过消息代理实现了分布式系统间的消息传递和事件广播,从而实现了动态刷新配置的功能。

☀️1.3.3 Spring Cloud Bus 动态刷新配置(全局广播)
🌈1.3.3.1 服务端配置

1、pom.xml添加依赖

<!--添加消息总线(Bus)对 RabbitMQ 的支持-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--添加Spring Boot actuator 监控模块的依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、application.yml添加配置信息

##### RabbitMQ 相关配置,15672 是web 管理界面的端口,5672 是 MQ 的访问端口###########
spring:rabbitmq:host: 127.0.0.1port: 5672username: guestpassword: guest# Spring Boot 2.50对 actuator 监控屏蔽了大多数的节点,只暴露了 heath 节点,本段配置(*)就是为了开启所有的节点
management:endpoints:web:exposure:include: 'bus-refresh'
🌈1.3.3.2 客户端配置

1、pom.xml添加依赖

<!--添加消息总线(Bus)对 RabbitMQ 的支持-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

2、bootstrap.yml添加配置信息

##### RabbitMQ 相关配置,15672 是web 管理界面的端口,5672 是 MQ 的访问端口###########
spring: rabbitmq:host: 127.0.0.1port: 5672username: guestpassword: guest

3、新建新的客户端模块

其他和原本客户端模块一样,并在其配置文件 bootstrap.yml 中添加以下配置

#bootstrap.yml 是系统级别的,加载优先级高于 application.yml ,负责从外部加载配置并解析
server:port: 3366  #端口号为 3366
spring:application:name: spring-cloud-config-client-buscloud:config:label: master #分支名称name: config  #配置文件名称,config-dev.yml 中的 configprofile: dev  #配置文件的后缀名  config-dev.yml 中的 dev#这里不要忘记添加 http:// 否则无法读取uri: http://localhost:3344 #spring cloud 配置中心地址##### RabbitMQ 相关配置,15672 是web 管理界面的端口,5672 是 MQ 的访问端口###########rabbitmq:host: 127.0.0.1port: 5672username: guestpassword: guest
###################### eureka 配置 ####################
eureka:client: #将客户端注册到 eureka 服务列表内service-url:defaultZone: :7001/eureka/,:7002/eureka/,:7003/eureka/  #将服务注册到 Eureka 集群# Spring Boot 2.50对 actuator 监控屏蔽了大多数的节点,只暴露了 heath 节点,本段配置(*)就是为了开启所有的节点
management:endpoints:web:exposure:include: "*"   # * 在yaml 文件属于关键字,所以需要加引号

4、重启所有模块

使用浏览器访问:http://localhost:3355/getConfig、http://localhost:3366/getConfig



修改配置文件config-dev.yml

config:info: c.bianchengversion: 4.0

使用浏览器访问:http://localhost:3355/getConfig、http://localhost:3366/getConfig


☀️1.3.4 Spring Cloud Bus 动态刷新配置(定点通知)

使用 Spring Cloud Bus 实现定点通知的方法十分简单,只要我们在发送 POST 请求时使用以下格式即可。

http://{hostname}:{port}/actuator/bus-refresh/{destination}

修改配置文件config-dev.yml

config:info: c.bianchengversion: 4.0

向服务端发生命令

curl -X POST "http://localhost:3344/actuator/bus-refresh"

依次访问客户端


🚀感谢:给读者的一封信

亲爱的读者,

我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。

如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。

我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。

如果您愿意支持我的创作,请扫描下面二维码,您的支持将不胜感激。同时,如果您有任何反馈或建议,也欢迎与我分享。

再次感谢您的阅读和支持!

最诚挚的问候, “愚公搬代码”

更多推荐

【愚公系列】2023年11月 Java教学课程 195

本文发布于:2024-02-26 05:54:19,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1701536.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:愚公   课程   系列   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!