北京网站建设亿玛酷适合5,庆阳门户网,寻找客户的平台,深圳网站制作的公司哪家好文章目录 前言springCloud-2021.0.9 之 服务调服务 示例1. 主要用到的组件2. 效果3. 源码3.1. 服务A3.2. 服务B接受接口 前言 如果您觉得有用的话#xff0c;记得给博主点个赞#xff0c;评论#xff0c;收藏一键三连啊#xff0c;写作不易啊^ _ ^。 而且听说点赞的人每… 文章目录 前言springCloud-2021.0.9 之 服务调服务 示例1. 主要用到的组件2. 效果3. 源码3.1. 服务A3.2. 服务B接受接口 前言 如果您觉得有用的话记得给博主点个赞评论收藏一键三连啊写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差实在白嫖的话那欢迎常来啊!!! springCloud-2021.0.9 之 服务调服务 示例
这里我介绍一下我用到的springCloud 是2021.0.9版本。 Maven 依赖管理配置引入 Spring Cloud 的 BOMBill of Materials文件主要作用如下 版本统一通过引入 BOM 文件您可以统一管理项目中所有 Spring Cloud 相关依赖的版本避免版本冲突和不一致。 简化依赖声明在子模块中您无需显式指定 Spring Cloud 相关依赖的版本号Maven 会自动从 BOM 中获取版本信息。
与以前的引入方式相比这种方法提供了更好的版本控制和依赖管理特别是在处理多个子模块和复杂的依赖关系时能够有效减少手动管理版本的复杂性。
1. 主要用到的组件
Spring Cloud OpenFeign 这是一个声明式的 REST 客户端使得调用其他服务的 REST API 变得非常简单。通过 FeignClient 注解可以方便地定义 HTTP 接口自动实现与其他服务的调用。Fein 配合 Ribbon负载均衡使用时可以轻松实现跨服务的调用。
Spring Cloud Eureka Eureka 是一个服务注册与发现组件。服务启动时会向 Eureka Server 注册自己而需要访问其他服务时可以通过 Eureka 来查找服务的实例。Eureka 可以帮助实现服务的动态发现和负载均衡。
Spring Cloud Circuit Breaker: 统一的熔断器框架它允许你更方便地实现和管理服务调用中的容错机制。熔断器的核心功能是当某个服务出现故障例如超时、异常时熔断器会短时间内停止对该服务的调用从而防止服务间的连锁故障允许系统在一定程度上继续运行。
Spring Cloud LoadBalancer: 是 Spring Cloud 中的一个客户端负载均衡器它提供了一种新的方式来替代 Ribbon用于在服务间调用时实现负载均衡。它的目标是让负载均衡的实现更加简单灵活并且易于与 Spring Cloud 的其他组件集成。
2. 效果 测试链路从postmain 发起 调用到 GateWay 后调到 服务A 然后通过open-Feign 到服务B下面是我准备的三个服务: 网关:SPRINGCLOUD-GATEWAY 服务A:SPRINGCLOUDSERVICEA 服务B:SPRINGCLOUDSERVICEB
发起请求: http://127.0.0.1:8809/springCloudServiceA/api/test/weifuw/xxx 返回:
{success: true,code: 0,message: 操作成功,data: 路径 xxx!
}查看zipkin: 调取网关的接口:
调取服务A的接口: 调取服务B的接口: 3. 源码
3.1. 服务A
pom:
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.6.15/version/parentgroupIdorg.example/groupIdartifactIdspringCloud-service-A/artifactIdversion1.0-SNAPSHOT/versionnamespringCloud-service-A/namepropertiesjava.version1.8/java.versionspring-cloud.version2021.0.9/spring-cloud.versionmybatis.version2.1.3/mybatis.version/propertiesdependencyManagementdependenciesdependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-dependencies/artifactIdversion${spring-cloud.version}/versiontypepom/typescopeimport/scope/dependency!-- 添加 Spring Cloud Resilience4j BOM --dependencygroupIdio.github.resilience4j/groupIdartifactIdresilience4j-bom/artifactIdversion1.7.0/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagementdependencies!--健康检查--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency!-- 热部署模块 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-devtools/artifactIdoptionaltrue/optional !-- 这个需要为 true 热部署才有效 --/dependency!--mysql--dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency!--多数据源--dependencygroupIdcom.baomidou/groupIdartifactIddynamic-datasource-spring-boot-starter/artifactIdversion3.5.1/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.1/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIddruid-spring-boot-starter/artifactIdversion1.1.22/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.28/version/dependency!--aop--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency!--feign 远程调用--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId/dependency!--注册中心客户端--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency!--日志追踪--dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-sleuth/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-sleuth-zipkin/artifactId/dependency!-- Spring Cloud Circuit Breaker 和 Spring Cloud LoadBalancer 来替代 Hystrix 和 Ribbon start --!-- Spring Cloud LoadBalancer --dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-loadbalancer/artifactId/dependency!-- Spring Cloud Circuit Breaker with Resilience4j --dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-circuitbreaker-resilience4j/artifactId/dependencydependencygroupIdio.github.resilience4j/groupIdartifactIdresilience4j-spring-boot2/artifactId/dependencydependencygroupIdio.github.resilience4j/groupIdartifactIdresilience4j-spring/artifactId/dependency!-- Spring Cloud Circuit Breaker 和 Spring Cloud LoadBalancer 来替代 Hystrix 和 Ribbon end --!-- 整合 mybatis-plus--dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.2.0/version/dependencydependencygroupIdorg.mybatis.spring.boot/groupIdartifactIdmybatis-spring-boot-starter/artifactIdversion${mybatis.version}/version/dependencydependencygroupIdcn.hutool/groupIdartifactIdhutool-all/artifactIdversion5.7.14/version/dependencydependencygroupIdorg.apache.httpcomponents/groupIdartifactIdhttpclient/artifactIdversion4.5.13/version/dependencydependencygroupIdorg.hibernate/groupIdartifactIdhibernate-validator/artifactIdversion5.3.4.Final/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.22/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!--springfox start --dependencygroupIdorg.springdoc/groupIdartifactIdspringdoc-openapi-ui/artifactIdversion1.7.0/version/dependency!--springfox end --!-- 密码加密 --dependencygroupIdcom.github.ulisesbocchio/groupIdartifactIdjasypt-spring-boot-starter/artifactIdversion3.0.4/version/dependency!-- flyway --
!-- dependency--
!-- groupIdorg.flywaydb/groupId--
!-- artifactIdflyway-core/artifactId--
!-- version5.2.3/version--
!-- /dependency--/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdversion2.6.15/versionexecutionsexecutiongoalsgoalrepackage/goal/goalsphasepackage/phase/execution/executionsconfigurationexcludeDevtoolstrue/excludeDevtools/configuration/plugin/plugins/build/project
AppConfig:
package org.example.config;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;/**
* description: TODO
* author 杨镇宇
* date 2024/7/29 11:32
* version 1.0
*/Configuration
public class AppConfig {/*** 直接使用LoadBalanced注解创建一个负载均衡的RestTemplate实例*/BeanLoadBalancedpublic RestTemplate restTemplate() {return new RestTemplate();}
}
Resilience4JConfig:
package org.example.config;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;import java.time.Duration;/**
* description: Resilience4J Circuit Breakers 断路器提供默认配置
* author 杨镇宇
* date 2024/7/29 18:22
* version 1.0
*/
Configuration
public class Resilience4JConfig {Beanpublic CustomizerResilience4JCircuitBreakerFactory defaultCustomizer() {return factory - factory.configureDefault(id - new Resilience4JConfigBuilder(id).timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build()).circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build());}
}controller:
package org.example.controller;import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.example.exception.model.ResponseResult;
import org.example.service.TestOneService;
import org.example.vo.ScanVo;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/*** author yangzhenyu* */
OpenAPIDefinition(info io.swagger.v3.oas.annotations.info.Info(title 示例 API,version 1.0,description 这是一个示例 API 文档),tags {Tag(name Example, description 示例 API)}
)
Validated
RestController
Slf4j
RequestMapping(valueapi/test)
public class TestController {Resourceprivate TestOneService service;Operation(summary 测试微服务调用接口,description 测试微服务调用接口,responses {ApiResponse(responseCode 200,description 成功,content Content(mediaType application/json,schema Schema(implementation ResponseResult.class))),ApiResponse(responseCode 400, description 请求错误)})CrossOrigin(origins *) //处理跨域请求的注解RequestMapping(value /weifuw/{path}, method RequestMethod.GET)public ResponseResult weifuw(PathVariable(value path) String path){log.info(调用服务B参数:{},path);return service.scan(path);}}
service:
/**
* description: TODO
* author 杨镇宇
* date 2024/7/29 15:00
* version 1.0
*/public interface TestOneService {ResponseResult scan(String path);}
package org.example.service.impl;import org.apache.commons.lang3.StringUtils;
import org.example.client.SpringCloudServiceBClient;
import org.example.exception.model.ResponseResult;
import org.example.service.TestOneService;
import org.example.vo.ScanVo;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/**
* description: TODO
* author 杨镇宇
* date 2024/7/29 15:02
* version 1.0
*/
Service
public class TestOneServiceImpl implements TestOneService {Resourceprivate SpringCloudServiceBClient client;Overridepublic ResponseResult scan(String path) {ScanVo v1 ScanVo.builder().path(path).build();String scan client.scan(v1);if (StringUtils.isNotBlank(scan)){return ResponseResult.ok(scan);}return null;}
}
Client
package org.example.client;import org.example.vo.ScanVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;/**
* description: TODO
* author 杨镇宇
* date 2024/7/29 15:04
* version 1.0
*/
FeignClient(name springCloudServiceB, fallback SpringCloudServiceBClientFallback.class)
public interface SpringCloudServiceBClient {RequestMapping(value /api/test/scan, method RequestMethod.POST)String scan(RequestBody ScanVo scanVo);
}
package org.example.client;import org.example.exception.ExceptionEnum;
import org.example.exception.ResultCode;
import org.example.exception.throwtype.RunException;
import org.example.vo.ScanVo;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;/**
* description: TODO
* author 杨镇宇
* date 2024/7/29 15:13
* version 1.0
*/
Component
public class SpringCloudServiceBClientFallback implements SpringCloudServiceBClient{//自定义的降级处理逻辑Overridepublic String scan(ScanVo scanVo) {ResultCode r ExceptionEnum.FALLBACK_RESPONSE_ERROR;r.setDesc(---springCloudServiceB---- HttpStatus.SERVICE_UNAVAILABLE.getReasonPhrase());throw new RunException(r);}
}
yml:
server:port: 9008zipkin:base-url: http://127.0.0.1:9411/#让nacos把它当成一个URL而不要当做服务名discovery-client-enabled: false
eureka:instance:prefer-ip-address: true # 优先ip注册client:service-url:defaultZone: http://127.0.0.1:8761/eureka # 注册中心地址down:url: http://127.0.0.1:8761/actuator/service-registry?statusDOWN
feign:client:config:default:connectTimeout: 60000 # 连接超时时间单位毫秒readTimeout: 60000 # 读取超时时间单位毫秒circuitbreaker:enabled: true
resilience4j.circuitbreaker: # 保护服务不被外部不稳定的服务影响避免连锁故障。configs:default:slidingWindowSize: 50 # 滑动窗口的大小为 100。permittedNumberOfCallsInHalfOpenState: 10 # 在半开状态下允许10次调用以测试服务是否恢复正常。waitDurationInOpenState: 50s # 断路器在打开状态下等待50秒后尝试进入半开状态。failureRateThreshold: 60 # 如果失败率超过 60%则断路器会切换到打开状态。eventConsumerBufferSize: 10 # 用于事件消费的缓冲区大小设置为 10registerHealthIndicator: true # 是否注册健康指示器允许通过 /actuator/health 端点监控断路器状态。someShared: # 共享的配置模板slidingWindowSize: 50 # 滑动窗口的大小为 50即窗口内包含最近 50 次调用的数据。permittedNumberOfCallsInHalfOpenState: 10 # 在半开状态下允许 10 次调用来测试服务是否恢复正常。instances:springCloudServiceB:registerHealthIndicator: true # 注册健康指示器可以通过/actuator/health监控断路器状态。slidingWindowSize: 50 # 滑动窗口的大小为 100。minimumNumberOfCalls: 20 # 至少20次调用后开始计算失败率。permittedNumberOfCallsInHalfOpenState: 10 # 在半开状态下允许10次调用以测试服务是否恢复正常。waitDurationInOpenState: 50s # 断路器在打开状态下等待50秒后尝试进入半开状态。slidingWindowType: TIME_BASED #滑动窗口类型为时间基础型TIME_BASED即基于时间的窗口。
resilience4j.timelimiter: # 限制外部服务的响应时间防止服务被长时间挂起。configs:default:timeoutDuration: 2s # 设置操作的超时时间为 2 秒。如果操作在 2 秒内没有完成将会被取消。cancelRunningFuture: true # 是否在超时后取消正在运行的操作。instances:springCloudServiceB:timeoutDuration: 2s # 设置操作的超时时间为 2 秒。如果操作在 2 秒内没有完成将会被取消。cancelRunningFuture: true # 是否在超时后取消正在运行的操作。
spring:sleuth:zipkin:http:connect-timeout: 5000 # 连接超时设置为5秒read-timeout: 10000 # 读取超时设置为10秒application:name: springCloudServiceAcloud:loadbalancer:retry:enabled: true # 启用重试maxAttempts: 3 # 设置最大重试次数backoff:initialInterval: 1000 # 初始重试间隔时间毫秒maxInterval: 3000 # 最大重试间隔时间毫秒multiplier: 1.5 # 间隔时间增量因子service-instance-selector: random # 全局使用随机负载均衡策略datasource:dynamic: # druid连接池配置primary: master #默认数据源datasource:master: #主库配置username: TESTDB #TESTDBpassword: ENC(xuBgV6ZA7A6LSZ8PbaAFWg) #TESTDBdriver-class-name: ${datasource_driver_class_name:com.mysql.cj.jdbc.Driver}url: ${datasource_url:jdbc:mysql://127.0.0.1:3306/TESTDB?characterEncodingutf8useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneUTC}druid:initial-size: 5 #启动程序时在连接池中初始化多少个连接max-active: 20 #连接池中最多支持多少个活动会话min-idle: 5 #回收空闲连接时将保证至少有minIdle个连接max-wait: 60000 #程序向连接池中请求连接时,超过maxWait的值后认为本次请求失败即连接池filters: stat,wall,slf4jslave: #从库配置username: TESTDB #TESTDBpassword: ENC(xuBgV6ZA7A6LSZ8PbaAFWg) #TESTDBdriver-class-name: ${datasource_driver_class_name:com.mysql.cj.jdbc.Driver}url: ${datasource_url:jdbc:mysql://127.0.0.1:3306/TESTDB?characterEncodingutf8useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneUTC}druid:initial-size: 5 #启动程序时在连接池中初始化多少个连接max-active: 20 #连接池中最多支持多少个活动会话min-idle: 5 #回收空闲连接时将保证至少有minIdle个连接max-wait: 60000 #程序向连接池中请求连接时,超过maxWait的值后认为本次请求失败即连接池filters: stat,wall,slf4jspringdoc:api-docs:path: /v3/api-docsswagger-ui:path: /swagger-ui.html
management:endpoints:web:exposure:include: health, metrics, info, httptrace#jasypt:
# encryptor:
# property: resolver # 使用自定义的 EncryptablePropertyResolver
# bean: encryptionPropertyResolver
#logging:
# level:
# org.springframework: DEBUGjasypt:encryptor:#password 本地环境将密钥放入yml文件中生产需要jvm携带 -Djasypt.encryptor.passwordxxxxxpassword: yzy_user!1Uxalgorithm: PBEWithMD5AndDESiv-generator-classname: org.jasypt.iv.NoIvGenerator
3.2. 服务B接受接口 /*** author yangzhenyu* */
Validated
RestController
Slf4j
RequestMapping(valueapi/test)
public class TestController {Operation(summary 测试接口,description 通过微服务调触发此测试接口,requestBody io.swagger.v3.oas.annotations.parameters.RequestBody(description 调用测试接口的对象,required true,content Content(mediaType application/json,schema Schema(implementation ScanVo.class))),responses {ApiResponse(responseCode 201, description 测试成功),ApiResponse(responseCode 400, description 请求错误)})CrossOrigin(origins *) //处理跨域请求的注解RequestMapping(value /scan, method RequestMethod.POST)public String scan(Validated RequestBody ScanVo scanVo) {String format String.format(路径 %s!, scanVo.getPath());log.info(format);return format;}}