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

昆明网络公司排行榜大连seo关键词排名

昆明网络公司排行榜,大连seo关键词排名,赵公口网站建设公司,网站建设策划书总结🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、OpenFeign OpenFeign 是 Spring Cloud 生态中的声明式 HTTP 客户端工具,基于 Netflix Feign 开发。它通过接口和注解定义 HTTP 请求,简化了服…

    🔥个人主页: 中草药

🔥专栏:【中间件】企业级中间件剖析


 一、OpenFeign

OpenFeign 是 Spring Cloud 生态中的声明式 HTTP 客户端工具,基于 Netflix Feign 开发。它通过接口和注解定义 HTTP 请求,简化了服务间的 RESTful 调用,并与 Ribbon(负载均衡)、Hystrix(熔断)等组件无缝集成。

快速上手

观察之前RestTemplate所写的代码

public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);String url = "http://product-service/product/"+ orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;
}

虽然RestTemplate对HTTP进行封装之后,已经build直接使用HTTPClient简单方便许多,但是仍然存在一些问题。

1、需要拼接URL,灵活性较高,但是封装臃肿,URL复杂时,容易出错

2、代码的可读性差,风格不统一

此处我们可以用到OpenFeign

添加依赖

<!-- Spring Cloud OpenFeign -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启用 OpenFeign

在 Spring Boot 启动类添加 @EnableFeignClients

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

定义 Feign 客户端接口

@FeignClient(value = "product-service",path = "/product")
public interface ProductApi {@RequestMapping("/{productId}")ProductInfo getProductInfo(@PathVariable("productId") Integer productId);
}

value: 指定FeignClient的名称,用于服务发现,feign的底层会使用Spring Cloud LoadBalance进行负载均衡,也可以使用url

path:定义当前FeignClient的统一前缀

调用 Feign 客户端

@Slf4j
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate ProductApi productApi;public OrderInfo selectOrderById(Integer orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);ProductInfo productInfo = productApi.getProductInfo(orderInfo.getProductId());orderInfo.setProductInfo(productInfo);return orderInfo;}
}

参数传递

@FeignClient(value = "product-service",path = "/product")
public interface ProductApi {@RequestMapping("/{productId}")ProductInfo getProductInfo(@PathVariable("productId") Integer productId);//传递单个参数@RequestMapping("/p1")public String p1(@RequestParam("id") Integer id);//传递多个参数@RequestMapping("/p2")public String p2(@RequestParam("id") Integer id,@RequestParam("name") String name);//传递对象@RequestMapping("/p3")public String p3(@SpringQueryMap ProductInfo productInfo);//传递json@RequestMapping("/p4")public String p4(@RequestBody ProductInfo productInfo);
}

注意:@RequestParam 不能省略,作为参数绑定 

抽取方式

官方推荐 Feign 的使用方式为继承的方式,但企业开发中,更多是把 Feign 接口抽取为一个独立的模块(做法和继承相似,但理念不同)。
继承

创建一个新的module,并引入依赖,编写相关 interface(内容基本和原服务调用方所用的代码一样)

public interface ProductInterface {@RequestMapping("/{productId}")ProductInfo getProductInfo(@PathVariable("productId") Integer productId);//传递单个参数@RequestMapping("/p1")public String p1(@RequestParam("id") Integer id);//传递多个参数@RequestMapping("/p2")public String p2(@RequestParam("id") Integer id,@RequestParam("name") String name);//传递对象@RequestMapping("/p3")public String p3(@SpringQueryMap ProductInfo productInfo);//传递json@RequestMapping("/p4")public String p4(@RequestBody ProductInfo productInfo);
}

再通过maven打包

引入相关依赖

<dependency><groupId>org.example</groupId><artifactId>product-api</artifactId>4    <version>1.0-SNAPSHOT</version><scope>compile</scope>
</dependency>

 修改服务消费方中ProductApi,ProductInfo的路径为 product-api 中的路径

并修改ProductApi的代码,继承引入jar包的ProductInterface

@FeignClient(value = "product-service",path = "/product")
public interface ProductApi extends ProductInterface {}

 修改服务提供方Controller的代码,实现ProductInterface接口

@RestController
@RequestMapping("/product")
public class ProductController implements ProductInterface {@Autowiredprivate ProductService productService;@RequestMapping("/{productId}")public ProductInfo getProductInfo(@PathVariable("productId") Integer productId) {return productService.selectProductById(productId);}//测试传递单个参数@RequestMapping("/p1")public String p1(Integer id){return "product-service 接受到参数 id:"+id;}//测试传递多个参数@RequestMapping("/p2")public String p2(Integer id,String name){return "product-service 接受到参数 id:"+id+",name:"+name;}//测试传递对象参数@RequestMapping("/p3")public String p3(ProductInfo productInfo){return "product-service 接受到参数 productInfo:"+productInfo;}//测试传递Json@RequestMapping("/p4")public String p4(@RequestBody ProductInfo productInfo){return "product-service 接受到参数 productInfo:"+productInfo;}
}

完成抽取 

抽取为独立模块
        将 Feign 的 Client 抽取为一个独立的模块,并把涉及到的实体类等都放在这个模块中,打成一个 Jar。服务消费方只需要依赖该 Jar 包即可。这种方式在企业中比较常见,Jar 包通常由服务提供方来实现。

创建一个新的module,并引入依赖,编写相关api

再通过maven打包

引入相关依赖

<dependency><groupId>org.example</groupId><artifactId>product-api</artifactId>4    <version>1.0-SNAPSHOT</version><scope>compile</scope>
</dependency>

 修改服务消费方中ProductApi,ProductInfo的路径为 product-api 中的路径

启动类添加扫描路径

@EnableFeignClients(clients = {ProductApi.class})
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

完成抽取

服务部署

修改数据库,Nacos 等相关配置

对两个服务进行打包

Maven 打包默认是从远程仓库下载的,product-api 这个包在本地,有以下解决方案:

上传到 Maven 中央仓库 (参考:如何发布 Jar 包到 Maven 中央仓库,比较麻烦)[不推荐]

搭建 Maven 私服,上传 Jar 包到私服 [企业推荐]

从本地读取 Jar 包 [个人学习阶段推荐]

前两种方法比较复杂,咱们使用第三种方式,要先修改服务消费方的pom文件

plugin

 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins>
</build>

 dependency

<dependency><groupId>org.example</groupId><artifactId>product-api</artifactId><version>1.0-SNAPSHOT</version><scope>system</scope><systemPath>C:/Users/18254/.m2/repository/org/example/product-api/1.0-SNAPSHOT/product-api-1.0-SNAPSHOT.jar</systemPath>
</dependency>

然后完成正常的打包部署运行操作即可

二、Gateway

API网关

        API网关是分布式系统中的一个核心组件,充当客户端与后端服务之间的“中间层”。它统一处理所有外部请求,有点类似于设计模式中的Facade模式(门面模式),负责路由、协议转换、安全控制、监控等功能,类似于系统的“守门人”和“交通指挥中心”。

网关核心功能:

权限控制:作为微服务的入口,对用户进行权限校验,校验失败则拦截。

动态路由:请求先经网关,网关不处理业务,按规则转发到微服务。

负载均衡:当目标服务有多个时,进行负载均衡操作。

限流:流量过高时,按配置放行流量,避免服务压力过大 。


快速上手

创建网关项目

引入相关依赖

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><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>

 添加Gateway的路由配置

server:port: 10030spring:application:name: gatewaycloud:nacos:discovery:server-addr: url:8848gateway:routes:- id: order-service #路由规则id,随便起,不重复即可uri: lb://order-service/predicates:- Path=/order/**,/feign/**- id: product-serviceuri: lb://product-service/predicates:- Path=/product/**

即可通过网关进行访问


 Route Predicate Factories

Predicate

  Predicate 是 Java 8 引入的函数式接口,位于 java.util.function 包中。它表示一个条件判断函数,接收一个输入参数,返回布尔值(true/false)。常用于集合过滤、数据校验和条件组合等场景。

@FunctionalInterface
public interface Predicate<T> {boolean test(T t);//...
}

核心方法

方法功能说明
boolean test(T t)对输入参数 t 进行条件判断,返回布尔值。
Predicate<T> and(Predicate)逻辑  操作,组合当前谓词和另一个谓词。
Predicate<T> or(Predicate)逻辑  操作,组合当前谓词和另一个谓词。
Predicate<T> negate()逻辑  操作,返回当前谓词的反义条件。
static <T> Predicate<T> isEqual(Object)静态方法,生成一个判断对象是否相等的谓词。

代码演示

public class PredicateTest {@Testpublic void test() {//Predicate<String> predicate = new StringPredicate();//匿名内部类
//        Predicate<String> predicate = new Predicate<String>() {
//
//            @Override
//            public boolean test(String s) {
//                return s==null || s.isEmpty();
//            }
//        };Predicate<String> predicate = s -> s==null || s.isEmpty();System.out.println(predicate.test(""));System.out.println(predicate.test("a"));}/*** negate 非*/@Testpublic void test2() {Predicate<String> predicate = s -> s==null || s.isEmpty();System.out.println(predicate.negate().test(""));System.out.println(predicate.negate().test("a"));}/*** or*/@Testpublic void test3() {Predicate<String> predicate = s -> "a".equals(s);Predicate<String> predicate2 = s -> "b".equals(s);System.out.println(predicate.or(predicate2).test("a"));System.out.println(predicate.or(predicate2).test("b"));System.out.println(predicate.or(predicate2).test("c"));}/*** and*/@Testpublic void test4() {Predicate<String> predicate = s -> s!=null && !s.isEmpty();Predicate<String> predicate2 = s -> s!=null && s.chars().allMatch(Character::isDigit);//判断每一个字符是否都是数字类型System.out.println(predicate.and(predicate2).test("aa"));System.out.println(predicate.and(predicate2).test("123"));}
}

  Route Predicate Factories

Route Predicate Factories :: Spring Cloud Gateway

在 Spring Cloud Gateway 中,Route Predicate Factories 是用于定义路由规则的核心组件。它们通过条件匹配(即“断言”)决定哪些请求应该被路由到特定的下游服务。每个断言工厂生成一个 Predicate<ServerWebExchange>,用于判断当前请求是否符合路由规则。

名称说明示例
After这个工厂需要一个日期时间 (Java 的 ZonedDateTime) 对象,匹配指定日期之后的请求

predicates:

- After=2017-01-20T17:42:47.789-07:00[America/Denver]

Before匹配指定日期之前的请求

predicates:

- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

Between匹配两个指定时间之间的请求,datetime2 的参数必须在 datetime1 之后

predicates:

- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

Cookie请求中包含指定 Cookie,且该 Cookie 值符合指定的正则表达式

predicates:

- Cookie=chocolate, ch.p

Header请求中包含指定 Header,且该 Header 值符合指定的正则表达式

predicates:

- Header=X-Request-Id, \d+

Host请求必须是访问某个 host (根据请求中的 Host 字段进行匹配)

predicates:

- Host=**.somehost.org,**.anotherhost.org

Method匹配指定的请求方式

predicates:

- Method=GET,POST

Path匹配指定规则的路径

predicates:

- Path=/red/{segment},/blue/{segment}

Remote Addr请求者的 IP 必须为指定范围

predicates:

- RemoteAddr=192.168.1.1/24


Gateway Filter Factories

GatewayFilter Factories :: Spring Cloud Gateway

在 Spring Cloud Gateway 中,Gateway Filter Factories 是用于处理请求和响应的核心组件。它们可以对请求进行修改(如添加请求头、重写路径)或对响应进行增强(如添加响应头、记录日志),从而实现流量控制、安全防护、数据转换等功能。过滤器分为两类:

  • Gateway Filter:作用于特定路由的过滤器。

  • Global Filter:全局过滤器,对所有路由生效。

Gateway Filter

 快速上手

spring:application:name: gatewaycloud:nacos:discovery:server-addr: url:8848gateway:routes:- id: order-service #路由规则id,随便起,不重复即可uri: lb://order-service/predicates:- Path=/order/**,/feign/**- After=2025-03-20T17:45:02.565907200+08:00[Asia/Shanghai]filters:- AddRequestParameter=userName,test

此时发送请求会自动加上参数

@Slf4j
@RestController
@RequestMapping("/feign")
public class FeignController {@Autowiredprivate ProductApi productApi;@RequestMapping("/o1")public String o1(Integer id,String userName){log.info("接收到过滤器添加的参数,userName:{}",userName);return productApi.p1(id);}
}

 以下是部分常见过滤器的说明

名称说明示例
AddRequestHeader为当前请求添加 Header- AddRequestHeader=X-Request-red, blue
参数: Header 的名称及值
AddRequestParameter为当前请求添加请求参数- AddRequestParameter=red, blue
参数:参数的名称及值
AddResponseHeader为响应结果添加 Header- AddResponseHeader=X-Response-Red, Blue
参数: Header 的名称及值
RemoveRequestHeader从当前请求删除某个 Header- RemoveRequestHeader=X-Request-Foo
参数: Header 的名称
RemoveResponseHeader从响应结果删除某个 Header- RemoveResponseHeader=X-Response-Foo
参数: Header 的名称
RequestRateLimiter为当前网关的所有请求执行限流过滤,如果被限流,默认响应 HTTP 429-Too ManyRequests。默认提供了 RedisRateLimiter 的限流实现,采用令牌桶算法实现限流功能。此处不做具体介绍

filters:

  - name: RequestRateLimiter

   args:

    redis-rate-limiter.replenishRate: 10

redis-rate-limiter.burstCapacity: 20

redis-rate-limiter.requestedTokens: 1
redis-rate-limiter.replenishRate:令牌桶填充速度,即每秒钟允许多少个请求 (不丢弃任何请求)
redis-rate-limiter.burstCapacity:令牌桶容量,即每秒钟最大能够执行的请求数量 (不丢弃任何请求),将此值设置为零将阻止所有请求
redis-rate-limiter.requestedTokens:每次请求占用几个令牌,默认为 1

Retry针对不同的响应进行重试。当后端服务不可用时,网关会根据配置参数来发起重试请求

filters:

  - name: Retry

   args:

     retries: 3

     statuses: BAD_REQUEST
retries: 重试次数,默认为 3
status:HTTP 请求返回的状态码,针对指定状态码进行重试,对应 org.springframework.http.HttpStatus

RequestSize设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large

filters:

  - name: RequestSize

   args:

     maxSize: 5000000
请求包大小,单位为字节

默认过滤器添加一个 filter 并将其应用于所有路由,这个属性需要一个 filter 的列表,详细参考后续内容-

Default Filters

举例 

server:port: 10030spring:application:name: gatewaycloud:nacos:discovery:server-addr: url:8848gateway:routes:- id: order-service #路由规则id,随便起,不重复即可uri: lb://order-service/predicates:- Path=/order/**,/feign/**- After=2025-03-20T17:45:02.565907200+08:00[Asia/Shanghai]filters:- AddRequestParameter=userName,test- id: product-serviceuri: lb://product-service/predicates:- Path=/product/**default-filters: #对全部生效- name: Retryargs:retries: 3statuses: BAD_GATEWAY

此处配置后,如若接受到BAD_GATEWAY(502)将会重试3次

@Slf4j
@RestController
@RequestMapping("/feign")
public class FeignController {@Autowiredprivate ProductApi productApi;@RequestMapping("/o1")public String o1(Integer id, String userName, HttpServletResponse response) {log.info("接收到过滤器添加的参数,userName:{}",userName);response.setStatus(502);return productApi.p1(id);}
}

 Global Filter

         在 Spring Cloud Gateway 中,Global Filter 是一种作用于所有路由的全局过滤器,用于统一处理请求和响应。与路由级别的过滤器(GatewayFilter)不同,全局过滤器无需绑定到特定路由,全局过滤器通常用于实现与安全性,性能监控和日志记录等相关的全局功能。

快速上手

添加依赖

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

添加配置

spring:cloud:gateway:metrics:enabled: true
management:endpoints:web:exposure:include: "*"endpoint:health:show-details: alwaysshutdown:enabled: true

测试结果

localhost:10030/actuator 显示所有监控的信息链接


  过滤器的执行顺序

        一个项目中,既有GatewayFilter,又有GlobalFilter时,在请求路由后,网关会把当前项目中的GatewayFilter和GlobalFilter合并到一个过滤器链(集合)中,并进行排序,依次执行过滤器。

        每一个过滤器都必须指定一个 int 类型的 order 值,默认值为 0,表示该过滤的优先级. order 值越小,优先级越高,执行顺序越靠前。

  • Filter 通过实现 Order 接口或者添加 @Order 注解来指定 order 值。
  • Spring Cloud Gateway 提供的 Filter 由 Spring 指定。用户也可以自定义 Filter,由用户指定。
  • 当过滤器的 order 值一样时,会按照 defaultFilter > GatewayFilter > GlobalFilter 的顺序执行。 

自定义过滤器

自定义GatewayFilter

        自定义GatewayFilter,需要去实现对应的接口GatewayFilterFactory,Spring Boot默认帮我们实现的抽象类是AbstractGatewayFilterFactory,可以直接使用

代码示例

@Data
public class CustomConfig {private String name;
}
@Slf4j
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomConfig> implements Ordered {public CustomGatewayFilterFactory() {super(CustomConfig.class);}/*过滤器的核心方法*/@Overridepublic GatewayFilter apply(CustomConfig config) {return new GatewayFilter() {/*** exchange ServerWebExchange: HTTP请求-响应交互契约,提供了对HTTP请求和响应的访问* chain GatewayFilterChain:过滤器链* Mono 是Reactor中的核心类,数据流的发布者,Mono最多只触发一个事件,可以把Mono用在异步完成任务时,发出通知* chain.filter(exchange); 执行请求* Mono.fromRunnable() 创建一个包括Runnable元素的数据流*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//Pre类型 执行请求 Post类型//pre类型过滤器的代码逻辑log.info("Pre Filter , config:{}", config);return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("Post Filter ... ");//post类型过滤器的代码逻辑}));}};}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE;}
}

进行配置

这几个类之间的匹配关系是 

 测试结果

自定义GlobalFilter

         GlobalFilter的实现相对比较简单,不需要额外的配置,只需要实现GlobalFilter接口,自动会过滤所有的filter

代码示例

@Slf4j
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("pre Global Filter...");return chain.filter(exchange).then(Mono.fromRunnable(() -> {log.info("post Global Filter...");}));}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE;}
}

 无需额外配置,即可测试代码


三、分布式多机部署

mysql

mysql 在默认情况下,只允许本地连接,即localhost,如果需要其他服务器连接到mysql,需要mysql对这个服务器授权

grant 权限 on 数据库对象 to ⽤⼾

举例

--创建用户bite,并设置密码,此步可省略
CREATE USER 'test'@'%' IDENTIFIED BY 'test@java.182';
-- 对bite用户授权
--*.*表示所有库的所有表,也可以指定库和表
--%表示IP,%表示允许所有IP访问,也可以指定IP
GRANT ALL ON *.* To 'bite'@'%';
-- 让修改生效
FLUSH PRIVILEGES:

 同时需要修改配置文件的bind-address

把bind-address= 127.0.0.1改为bind-address= 0.0.0.0

重启服务-sudo systemctl restart mysql

可以在本机mysql进行测试

#把110.41.51.65改成⾃⼰服务器的IP -u改成设置的账号名 -p后是对应的密码
mysql -h ip -P port -u testuser -p

其他部署基本与正常的部署大差不差,关键注意配置文件相关ip地址的修改

注意 :由于nacos有时会注册的是内网ip ,而实际往往多个服务器不在一个局域网 我们可以在启动服务的时候指定一下

nohup java -jar order-service.jar --spring.cloud.nacos.discovery.ip=ip >logs/order.log &

 今天应做的事没有做,明天再早也是耽误了。——裴斯泰洛齐

🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐

  制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸 

http://www.dtcms.com/wzjs/6432.html

相关文章:

  • 网站开发需要用到的技术服务推广软文
  • 外贸网站推广平台排名前十名公司优化是什么意思?
  • 太原网站优化哪家专业外链link
  • 广州手机网站建设公司seo优化方案
  • app网站如何做推广磁力搜索器在线
  • 网站建设公司昆明今日国内新闻最新消息
  • 六安政务中心网站志鸿优化网
  • 做彩平图的素材那个网站有哪些店铺适合交换友情链接
  • 广州做淘宝的化妆品网站seo快速工具
  • 登陆网站怎么做推广网站有效的方法
  • 如何对新开网站做收录线上平台推广方式
  • wordpress jekyll 选择seo优化文章网站
  • 重庆做网站changeke长沙网站seo优化
  • 个人网站可以挂广告吗个人网站seo入门
  • 网站公安局备案 教程seo优化标题
  • 网页设计公司开设需要投资多少钱电商网站商品页的优化目标是什么
  • 做爰免费视频网站百度集团股份有限公司
  • 安卓下载百度关键词优化大
  • 大德通众包 做网站怎么样网络营销有哪些推广方法
  • 怎么做熊掌号网站cnzz
  • 北京商地网站建设公司谷歌浏览器 免费下载
  • 企业网站建设策划如何自己做网络推广
  • 长春百度网站优化门户网站制作
  • app 展示网站百度服务商平台
  • 链接提交入口抖音seo软件工具
  • 网站优化公司最新seo课程
  • jsp班级新闻网站代做天津网络推广seo
  • 上海网站建设-网建知识电商平台如何推广运营
  • 怎样做多商户网站竞价排名是什么意思
  • 网站logo怎么做最清楚2023b站推广大全