好记性,不如烂笔头

万物寻其根,通其堵,便能解其困。
  博客园  :: 新随笔  :: 管理

Spring colud的构建(2025年11月重新整理笔记版)

Posted on 2025-11-23 18:01    阅读(2)  评论(0)    收藏  举报

旧版笔记:Spring colud的构建,详情跳转查看

一、创建pom项目

界面截图:

image

 修改pom.xml引入项目依赖:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <!-- 引入依赖 -->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
    <relativePath />
  </parent>

  <groupId>com.namejr</groupId>
  <artifactId>Web_GatherCould</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!-- spring cloud中,父工程使用pom -->
  <packaging>pom</packaging>

  <name>Web_GatherCould</name>
  <url>http://maven.apache.org</url>
  <modules>
    <module>Web_PublicCould</module>
  </modules>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </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.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.10.14</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <!-- 数据库相关插件 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.2</version>
    </dependency>

    <!-- openapi文档 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-ui</artifactId>
      <version>1.6.9</version>
    </dependency>
  </dependencies>
  <!-- 引入spring-cloud依赖,通过dependencyManagement管理 -->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2021.0.9</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2021.0.6.0</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

二、Nacos

1.注册中心和配置中心

创建子模块:

022be490-dcac-459b-87b7-50906757f1b0

26720057-ddac-4cb2-b78d-8d2177a38527

 目录结构(无关的就不记录了):

9b4b7813-8b5c-471a-9f38-0359d86ff815

Web_PublicCould中pom.xml配置:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.namejr</groupId>
        <artifactId>Web_GatherCould</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>Web_PublicCould</artifactId>
    <packaging>war</packaging>

    <name>Web_PublicCould</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- nacos注册中心子服务依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- nacos配置中心子服务依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- 自2.4版本之后,默认bootstrap处于禁用状态,需要手动引入,否则会报:Add a spring.config.import=nacos: property to your configuration. -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.yml</include>
                    <include>**/*.xml</include>
                    <include>**/*.json</include>
                    <include>**/*.js</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <!-- 注册webapp目录为资源目录 -->
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/**</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

PublicCouldConfig.java

package com.namejr.base;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/** Nacos配置中心配置内容,这是一种方式,
 * 另外一种是@RefreshScope,直接使用@Value("${common.configuration.adjustConfig}")获取
 *  */
@Component
@ConfigurationProperties(prefix = "common.configuration")
public class PublicCouldConfig {
    public String getAdjustConfig() {
        return adjustConfig;
    }

    public void setAdjustConfig(String adjustConfig) {
        this.adjustConfig = adjustConfig;
    }
    private String adjustConfig;
}

PublicController.java

package com.namejr.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api/public")
@Tag(name = "PublicController", description = "通用公共控制器")
@RefreshScope
public class PublicController {
    private static final Logger logger = LoggerFactory.getLogger(PublicController.class);

    @Value("${comment.configuration.testButton}")
    private Integer testButton;
    @Value("${common.configuration.adjustConfig}")
    private String adjustConfig;

    @RequestMapping(value = "/serviceTime", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String serviceTime() {
        return DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
    }

    /** 测试动态修改Nacos是否能正常获取 */
    @RequestMapping(value = "/runNacosConfig", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String runNacosConfig() {
        return adjustConfig;
    }
}

bootstrap.properties

# 配置Nacos服务名称(漏掉配置这个玩意可能会导致无法自动获取配置更新)
spring.application.name=publicCould

# Nacos配置中心服务地址
spring.cloud.nacos.config.server-addr=127.0.0.1:18848
spring.cloud.nacos.config.username=nacos
spring.cloud.nacos.config.password=nacos
# 指定后缀
spring.cloud.nacos.config.file-extension=properties
# 动态刷新配置(新版本不再使用refresh-enable,改成下面两个)
#spring.cloud.nacos.config.refresh-enable=true
spring.cloud.nacos.config.enabled=true
spring.cloud.nacos.config.refresh-enabled=true
# 指定开发环境
spring.cloud.nacos.config.namespace=public
# 指定分组
spring.cloud.nacos.config.group=DEFAULT_GROUP

46aa4dc2-9f33-4990-804c-a020a371ba7b

 610289f3-5d17-4293-8afa-6b63baad8007

 

application.properties

# 端口号
server.port=11101
# 配置日志
logging.config=classpath:logback-spring.xml
# 版本号
comment.configuration.version=20251122
# 测试按钮
comment.configuration.testButton=1

# 配置Nacos服务名称
spring.application.name=publicCould

# Nacos服务注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:18848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# 心跳由默认的5s改为10s
spring.cloud.nacos.discovery.heart-beat-interval=10000
# 心跳由默认的15s改为20s。在20s没有收到客户端的心跳就认为客户端不不健康状态
spring.cloud.nacos.discovery.heart-beat-timeout=20000
# 如果超过60s没有收到客户端的心跳,nacos服务端变会把客户端的服务实例删除。
spring.cloud.nacos.discovery.ip-delete-timeout=60000

 2.配置消费者(使用负载均衡)

 e0cc4f2a-b1d9-488e-8e50-e88ef40710d1

 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.namejr</groupId>
        <artifactId>Web_GatherCould</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>Web_Consumer</artifactId>
    <packaging>jar</packaging>

    <name>Web_Consumer</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- nacos注册中心子服务依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入负载均衡处理 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>
</project>

application.properties

# 端口号
server.port=11102
# 配置日志
logging.config=classpath:logback-spring.xml

# mysql数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3307/web_test?characterEncoding=UTF-8&allowMultiQueries=true&&useAffectedRows=true&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username=test_user_id
spring.datasource.password=test_user_pwd
# 连接池配置
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计
# "stat,wall,log4j"中的wall用于防火墙,如果开启,那么无法执行多条SQL语句;log4j也应该去掉,因为新版的配置已经发生改变
spring.datasource.filters=stat
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 合并多个DruidDataSource的监控数据
#spring.datasource.useGlobalDataSourceStat=true

# mybatis配置
mybatis.type-aliases-package=com.namejr.bean
mybatis.mapper-locations=classpath:/dao/*.xml

# 配置(Nacos服务)名称
spring.application.name=consumer

# Nacos服务注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:18848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# 心跳由默认的5s改为10s
spring.cloud.nacos.discovery.heart-beat-interval=10000
# 心跳由默认的15s改为20s。在20s没有收到客户端的心跳就认为客户端不不健康状态
spring.cloud.nacos.discovery.heart-beat-timeout=20000
# 如果超过60s没有收到客户端的心跳,nacos服务端变会把客户端的服务实例删除。
spring.cloud.nacos.discovery.ip-delete-timeout=60000

BalanceRestTemplateConfig.java

package com.namejr.base;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/* 负载均衡的RestTemplate */
@Configuration
public class BalanceRestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getLoadBalancedRestTemplate(){
        return new RestTemplate();
    }
}

PublicController.java

package com.namejr.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping(value = "/api/public")
@Tag(name = "PublicController", description = "通用公共控制器")
@RefreshScope
public class PublicController {
    private static final Logger logger = LoggerFactory.getLogger(PublicController.class);

    // 因为和非负载均衡Bean(getRestTemplate)冲突,故使用QualiFier限定
    @Qualifier("getLoadBalancedRestTemplate")
    @Autowired
    private RestTemplate brestTemplate;
    @RequestMapping(value = "/getStringByLoadBalanced", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String serviceTime() {
        // 格式: http://服务名称/port
        return brestTemplate.getForObject("http://publicCould/api/public/runNacosConfig",String.class);
    }

}

f6fe69d4-9eda-4a35-b821-40d0dbc23a4a

 三、网关

 子模块截图

image

 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.namejr</groupId>
    <artifactId>Web_GatherCould</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <artifactId>Web_GatewayCould</artifactId>
  <packaging>jar</packaging>

  <name>Web_GatewayCould</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- nacos注册中心子服务依赖包 -->
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- 添加网关依赖 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- 添加 Spring Boot Actuator 监控 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- 如果配置中要使用lb://URL,那么这里的负载均衡需要显示依赖进去 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

application.properties(法一:通过配置文件配置网关,下面有通过bean进行配置的,目前没使用)

# 端口号
server.port=11100
# 配置日志
logging.config=classpath:logback-spring.xml

# actuator 监控 http://localhost:11100/actuator/gateway/routes
management.endpoints.web.exposure.include=*

# 配置(Nacos服务)名称
spring.application.name=gateway

# Nacos服务注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:18848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# 心跳由默认的5s改为10s
spring.cloud.nacos.discovery.heart-beat-interval=10000
# 心跳由默认的15s改为20s。在20s没有收到客户端的心跳就认为客户端不不健康状态
spring.cloud.nacos.discovery.heart-beat-timeout=20000
# 如果超过60s没有收到客户端的心跳,nacos服务端变会把客户端的服务实例删除。
spring.cloud.nacos.discovery.ip-delete-timeout=60000

# 网关相关配置
# 在application.yml中将web应用类型设置为REACTIVE:
spring.main.web-application-type=reactive

# gateway开启服务注册和发现功能,并自动根据服务发现每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务
# spring.cloud.gateway.discovery.locator.enabled=true
# 是将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了),比如以/service-hi/*的请求路径被路由转发到服务名为service-hi的服务上。
# spring.cloud.gateway.discovery.locator.lower-case-service-id=true

# id:唯一即可
spring.cloud.gateway.routes[0].id=publicCould
# 路由目标地址
# 方式一:spring.cloud.gateway.routes[0].uri=http://127.0.0.1:11101
# 方式二:使用负载均衡,格式:lb://+服务名称
spring.cloud.gateway.routes[0].uri=lb://publicCould
# 路由断言,也就是路由规则,符合下面的路由规则将会使用对应routes下的uri,如本例子就会路由到routes[0].uri=lb://publicCould
spring.cloud.gateway.routes[0].predicates[0]=Path=/wpc/**

spring.cloud.gateway.routes[1].id=consumer
spring.cloud.gateway.routes[1].uri=lb://consumer
spring.cloud.gateway.routes[1].predicates[0]=Path=/wc/**

StartApplication.java

package com.namejr;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class StartApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(StartApplication.class, args);
    }

    protected SpringApplicationBuilder configuer(SpringApplicationBuilder builder) {
        return super.configure(builder);
    }
}

访问各个服务,直接通过11100网关所在模块端口访问各个模块。

image

 法二:通过bean进行配置的,目前没使用

base/GatewayRouterConfig.java

package com.namejr.base;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayRouterConfig {

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder locatorBuilder){
        final RouteLocatorBuilder.Builder routes = locatorBuilder.routes();
        routes.route(baidu-> baidu.path("/wpc/**").uri("lb://publicCould"));
        return routes.build();
    }
}

 各种详细配置,可以查看该文章,写得比较详细:springcloud 入门 之网关 springcloud gateway - 码猿笔记 - 博客园 (cnblogs.com)

四、熔断

另注:下面采用的是properties的配置方式,如果需要使用重写Bean的方式,可以参照该博客:使用Spring Cloud和Resilience4j实现微服务容错与降级

pox.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.namejr</groupId>
        <artifactId>Web_GatherCould</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>Web_Consumer</artifactId>
    <packaging>jar</packaging>

    <name>Web_Consumer</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- nacos注册中心子服务依赖包 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入负载均衡处理 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!-- 熔断器:resilience4j -->
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-boot2</artifactId>
        </dependency>
        <!-- 需要引入aop,否则@CircuitBreaker不生效 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>
</project>

目标服务Web_PublicCould的serviceTime模拟耗时

@RequestMapping(value = "/serviceTime", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String serviceTime() {
        try{
            Thread.sleep(10000);
        }catch (Exception err){}
        return DateTime.now().toString("yyyy-MM-dd HH:mm:ss");
    }

application.properties

# 端口号
server.port=11102
# 配置日志
logging.config=classpath:logback-spring.xml

# 配置(Nacos服务)名称
spring.application.name=consumer

# Nacos服务注册中心地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:18848
spring.cloud.nacos.discovery.username=nacos
spring.cloud.nacos.discovery.password=nacos
# 心跳由默认的5s改为10s
spring.cloud.nacos.discovery.heart-beat-interval=10000
# 心跳由默认的15s改为20s。在20s没有收到客户端的心跳就认为客户端不不健康状态
spring.cloud.nacos.discovery.heart-beat-timeout=20000
# 如果超过60s没有收到客户端的心跳,nacos服务端变会把客户端的服务实例删除。
spring.cloud.nacos.discovery.ip-delete-timeout=60000

# 1、断路器
# slidingWindowSize用于定义滑动窗口的大小,直接影响失败率计算和熔断触发条件。
# 滑动窗口大小:控制统计失败请求的样本数量,窗口越大,熔断触发越谨慎。
# 失败率计算:当窗口内失败请求占比超过阈值(如50%)时触发熔断。
# 默认值:slidingWindowSize=100(可通过resilience4j.circuitbreaker.configs.default.slidingWindowSize修改)。
# 自定义设置:例如设置为6,表示每次统计最近3次请求的失败率。
# 窗口未满时:即使失败率超过阈值,熔断也不会触发(需满足minimumNumberOfCalls)。
# 窗口满后:失败率超过阈值立即熔断,例如6次请求中3次失败即触发。
resilience4j.circuitbreaker.instances.consumerService.sliding-window-size=6
# 设置了类型以根据请求计数保持断路器行为。
resilience4j.circuitbreaker.instances.consumerService.sliding-window-type=COUNT_BASED
# 决定启用断路器的失败百分比的 API 调用总数的最小值。我将其设置为5。假设前 5 个 API 调用中有 3 个 API 调用失败。这意味着 failureRateThreshold = (3/5) * 100 = 60%。
resilience4j.circuitbreaker.instances.consumerService.minimum-number-of-calls=5
# failureRateThreshold是熔断器触发保护机制的核心参数,用于判断服务是否因异常失败而需要熔断。默认值为50%,即当失败调用占比超过该阈值时,熔断器会从关闭状态切换到打开状态,拒绝后续请求。
# 阈值定义与计算:
# 公式:失败率 = (失败调用数 ÷ 总调用数) × 100%
# 触发条件:失败率 ≥ 阈值(如50%)时触发熔断。
resilience4j.circuitbreaker.instances.consumerService.failure-rate-threshold=50
# 当转换的正确时间到来时,它会自动将 OPEN 状态转换为 HALF OPEN 状态。
resilience4j.circuitbreaker.instances.consumerService.automatic-transition-from-open-to-half-open-enabled=true
# waitDurationInOpenState用于指定断路器从OPEN状态切换到HALF_OPEN状态的等待时间,单位毫秒。此配置使断路器在熔断后5秒内尝试恢复。
resilience4j.circuitbreaker.instances.consumerService.wait-duration-in-open-state=5000
# 在 HALF OPEN 状态下应发送的 LIMITED API 调用数。我将其设置为 3。因此,在 3 次 API 调用之后,如果失败,则断路器将再次进入 OPEN 状态。否则断路器将关闭,因为 rate-service 已启动。
resilience4j.circuitbreaker.instances.consumerService.permitted-number-of-calls-in-half-open-state=3
# ringBufferSizeInClosedState在关闭状态(CLOSED)下的环状缓冲区大小,用于记录请求的成功/失败状态。默认值为100,表示熔断器会统计最近100次请求的失败率来判断是否触发熔断。
# 失败率计算:熔断器通过缓冲区中的请求数据计算失败率。若缓冲区未填满(请求次数低于缓冲区大小),即使失败率超过阈值,也不会触发熔断。
# ‌阈值触发条件:失败率需达到failureRateThreshold(默认50%)且缓冲区已填满时,熔断器才会切换到OPEN状态。
resilience4j.circuitbreaker.instances.consumerService.ring-buffer-size-in-closed-state=5
# ringBufferSizeInHalfOpenState用于定义熔断器在半开状态(HALF_OPEN)下允许通过的请求数量,直接影响熔断器状态转换和故障恢复效率。
# 状态转换:当熔断器处于打开状态(OPEN)时,经过等待时间(waitDurationInOpenState)后会进入半开状态。此时,熔断器会允许最多ringBufferSizeInHalfOpenState个请求通过,根据这些请求的成功率决定是否恢复关闭状态(CLOSED)或重新进入打开状态 。 默认值:默认值为10,表示半开状态下最多允许10个请求通过 。
resilience4j.circuitbreaker.instances.consumerService.ring-buffer-size-in-half-open-state=3

# 2、限流器
# limitForPeriod用于定义每个刷新周期内允许的最大请求数。以下是核心要点:
# 作用:控制单位时间(由limitRefreshPeriod指定)内允许的最大请求次数。
# 示例:若limitForPeriod=2且limitRefreshPeriod=1s,则每秒最多允许2个请求。
resilience4j.ratelimiter.instances.consumerService.limit-for-period=2
# 用于定义令牌刷新的时间间隔,单位为毫秒(ms),默认值为500ms。
# 核心作用:
# 控制令牌刷新频率:在指定时间间隔内,系统会重新生成一定数量的令牌(由limitForPeriod定义),用于限制请求速率。
# 与limitForPeriod共同决定限流速率:例如,若limitRefreshPeriod=1s且limitForPeriod=2,则每秒最多允许2个请求。
resilience4j.ratelimiter.instances.consumerService.limit-refresh-period=1s
# 通常指请求在获取令牌时的最大等待时间,超过该时间则触发超时。具体实现和配置取决于使用的库(如Resilience4j或Guava)。
# 信号量模式:通过Semaphore限制并发请求数,超时后直接返回失败。
# 线程池模式:通过线程池限制并发数,超时后返回失败。
resilience4j.ratelimiter.instances.consumerService.timeout-duration=100ms

# 3、重试
# maxAttempts参数用于配置最大重试次数(包含初始调用)。
resilience4j.retry.instances.consumerService.max-attempts=3
# waitDuration用于配置重试间隔时间,即两次重试尝试之间的等待时长。默认值:若未显式配置,默认等待时长为500毫秒(500ms)。
resilience4j.retry.instances.consumerService.wait-duration=500ms

 

BalanceRestTemplateConfig.java

package com.namejr.base;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/* 负载均衡的RestTemplate */
@Configuration
public class BalanceRestTemplateConfig {
    // 不推荐使用,但是可以使用
    @Bean
    @LoadBalanced
    public RestTemplate getLoadBalancedRestTemplate(){
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(10000); // 设置连接超时时间(毫秒)
        requestFactory.setReadTimeout(10000); // 设置读取超时时间(毫秒)
        return new RestTemplate(requestFactory);
        // return new RestTemplate();
    }

    /* 推荐使用,目前还没用:在这个例子中,我们使用了WebClient,它是响应式编程的一部分,非常适合与Spring Cloud Load
    // pom.xml
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    // 引入:
    import org.springframework.web.reactive.function.client.WebClient;
    import org.springframework.web.reactive.function.client.WebClient.RequestBodyUriSpec;
    import reactor.core.publisher.Mono;

    // 配置bean:
    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
    // 使用案例:
    @Autowired
    private WebClient.Builder webClientBuilder;
    public Mono<String> postData(String url, Map<String, Object> requestBody) {
        return webClientBuilder
             .build()
             .post()
             .uri("http://SERVICE-NAME/api/path")
             .body(Mono.just(requestBody), Map.class)
             .retrieve()
             .bodyToMono(String.class);
    }
    */
}

 

PublicController.java

package com.namejr.controller;

import com.namejr.service.PublicCouldService;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/wc/public")
@Tag(name = "PublicController", description = "通用公共控制器")
public class PublicController {
    private static final Logger logger = LoggerFactory.getLogger(PublicController.class);
    @Autowired
    private PublicCouldService pcService;

    @RequestMapping(value = "/getStringByLoadBalanced", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String stringByLoadBalanced() {
        return pcService.runNacosConfig();
    }

    @RequestMapping(value = "/serviceTime", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
    public String serviceTime() {
        return pcService.serviceTime();
    }
}

PublicCouldService.java

package com.namejr.service;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class PublicCouldService {
    @Qualifier("getLoadBalancedRestTemplate")
    @Autowired
    private RestTemplate brestTemplate;

    public String runNacosConfig(){
        // get请求,格式: http://服务名称/port
        return brestTemplate.getForObject("http://publicCould/wpc/public/runNacosConfig",String.class);
        /** post请求:
         * HttpHeaders headers = new HttpHeaders();
         * headers.setContentType(MediaType.APPLICATION_JSON);
         * HttpEntity<Object> entity = new HttpEntity<>(requestBody, headers);
         * restTemplate.postForObject("http://SERVICE-NAME/api/path", entity, String.class);
         * */
    }

  // 测试断路器 @CircuitBreaker(name
= "consumerService",fallbackMethod = "serviceTimeOfCircuitBreaker") public String serviceTime(){ return "正常返回:"+brestTemplate.getForObject("http://publicCould/wpc/public/serviceTime",String.class); } /** 注意:@CircuitBreaker声明fallbackMethod方法时,参数需要Exception,否则会报下面错误:NoSuchMethodException * 2025-11-29 16:56:24.037 ERROR -- [io-11102-exec-2] [.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.reflect.UndeclaredThrowableException] with root cause * java.lang.NoSuchMethodException: class java.lang.String class com.namejr.service.PublicCouldService.serviceTimeOfCircuitBreaker(,class java.lang.Throwable) * */ public String serviceTimeOfCircuitBreaker(Exception err){ System.out.println(err.getMessage()); return "熔断返回:"+ DateTime.now().toString("yyyy-MM-dd HH:mm:ss"); } }
/** 模拟异常
     * 断路器:@CircuitBreaker
     * 限流:@RateLimiter
     * 重试:@Retry
     * */
    @CircuitBreaker(name = "consumerService",fallbackMethod = "serviceTimeOfCircuitBreaker")
    @RateLimiter(name = "consumerService")
    @Retry(name = "consumerService")
    public String serviceTime(){
        return "正常返回:"+brestTemplate.getForObject("http://publicCould/wpc/public/serviceTime",String.class);
    }

访问http://127.0.0.1:11100/wc/public/serviceTime

image

 

image

 

 

 

 

 

。。。待续。