当前位置: 首页> 健康> 知识 > 怎么制作自己的微信公众号_徐州网站建设策划_深圳百度推广公司_正规电商培训学校排名

怎么制作自己的微信公众号_徐州网站建设策划_深圳百度推广公司_正规电商培训学校排名

时间:2025/7/12 7:20:29来源:https://blog.csdn.net/weixin_73060900/article/details/142728096 浏览次数:0次
怎么制作自己的微信公众号_徐州网站建设策划_深圳百度推广公司_正规电商培训学校排名

概述

由来

在实际开发中,被调用方一般是将需要提供给外部的代码再次进行封装,而调用方则是根据提供的URL来进行调用开发。

在前面的组件介绍中,我们远程调用使用的是RestTemplate类中的方法。但是,使用此类来实现远程调用,我们需要在调用方进行拼接URL、封装请求等内容,并且每个程序猿的代码风格不同,这样不仅导致容易出错,还导致后期维护成本难,容易造成屎山代码。

综上所述,一种新型的组件横空出世。在调用方,它简单到像controller层调用service层一样;在被调用方,它只需一个注解就可以将被调用的服务和封装的接口绑定。这样,无论是服务提供方还是服务调用方,都大大减少了代码的开发。这个组件就是OpenFeign。

微服务之间的通信方式,通常有两种:RPC和HTTP。

在SpringCloud中,默认是使用HTTP来进行微服务的通信,最常用的实现形式有两种:

  • RestTemplate。
  • OpenFeign

功能

  • 支持SpringCloudLoadBalancer的负载均衡
  • 支持Sentinel和它的Fallback

代码案例

搭建商品服务

建模块

 写pom文件

采用的是Nacos + OpenFeign的组件。

<?xml version="1.0" encoding="UTF-8"?>
<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.wbz</groupId><artifactId>spring-cloud-test</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-provider-product-open-feign-8401</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--SpringBoot通用模块--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--Lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--Druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><!--MySQL驱动--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!--MP--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency><!--注册中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--配置中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--BootStrap.yml--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency></dependencies></project>

写yml文件

使用的是bootstrap.yml文件

server:port: 8401spring:application:name: cloud-provider-product-open-feign-8401cloud:nacos:server-addr: 127.0.0.1:8848discovery:service: ${spring.application.name}config:prefix: ${spring.application.name}file-extension: ymlprofiles:active: devmvc:pathmatch:matching-strategy: ant_path_matcherdatasource:url: jdbc:mysql://127.0.0.1:3306/cloud_product?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=trueusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/**Mapper.xmltype-aliases-package: com.wbz.domain

写主启动类

@MapperScan("com.wbz.mapper")
@SpringBootApplication
public class OpenFeignProductServerApplication8401 {public static void main(String[] args) {SpringApplication.run(OpenFeignProductServerApplication8401.class, args);}}

写业务类

// JavaBean
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("product_detail")
public class Product {@TableIdprivate Long id;@TableFieldprivate String productName;@TableFieldprivate Long productPrice;@TableFieldprivate Integer state;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;}// mapper接口
public interface ProduceMapper extends BaseMapper<Product> {
}// service接口
public interface ProductService extends IService<Product> {Product getProductById(Long productId);}// service实现类
@Service
public class ProductServiceImpl extends ServiceImpl<ProduceMapper, Product> implements ProductService {@Overridepublic Product getProductById(Long productId) {return this.getById(productId);}}// controller类
@RestController
@RequestMapping("/product")
public class ProductController {@Resourceprivate ProductService productService;@GetMapping("/query/{productId}")public Product getProductById(@PathVariable Long productId) {return this.productService.getProductById(productId);}}

项目启动之后,在Nacos的管理界面出现改服务就表示启动成功。 

搭建commons服务

在微服务开发中,一般某一个类可能会在多个服务中被调用,例如实体类。因此,我们就要自定义一个或者多个模块,把一些常用的,基础的类拿出来,封装成一个模块。这样,当我们其他服务进行使用时,引入一个pom依赖即可。

在个人开发中,我们直接install就会将构建好的模块放到本地maven仓库中,直接调用即可。在企业开发中,则是将写好的jar包放入到私服中,这样其他开发人员也可以进行调用。

由于我们的学习过程中的代码量非常小,因此我们就不建多个模块了,直接建一个模块,把远程调用的接口和实体类放到一起。

建模块

写pom文件 

<?xml version="1.0" encoding="UTF-8"?>
<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.wbz</groupId><artifactId>spring-cloud-test</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-commons</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--Lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--OpenFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--MP--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId></dependency></dependencies></project>

写业务类

// 商品类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("product_detail")
public class Product {@TableIdprivate Long id;@TableFieldprivate String productName;@TableFieldprivate Long productPrice;@TableFieldprivate Integer state;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;}
// 订单表
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("order_detail")
public class Order {@TableIdprivate Long id;@TableFieldprivate Long userId;@TableFieldprivate Long productId;@TableFieldprivate Integer num;@TableFieldprivate Long price;@TableFieldprivate Integer deleteFlag;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;@TableField@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;@TableField(exist = false)private Product product;}
// 远程调用的接口,服务调用方直接引入该模块的依赖,然后调用即可
@FeignClient(value = "cloud-provider-product-open-feign-8401", path = "/product")
public interface ProductFeignApi {@GetMapping("/query/{productId}")Product getProductById(@PathVariable("productId") Long productId);}

在cloud-commons模块搭建完成之后,在商品服务中删除实体类,然后引入该模块的依赖,观察是否够启动并调用成功。 

搭建订单服务

建模块

写pom文件

<?xml version="1.0" encoding="UTF-8"?>
<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.wbz</groupId><artifactId>spring-cloud-test</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-consumer-order-open-feign-84</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--注册中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--配置中心--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--bootstrap--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><!--OpenFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--负载均衡--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--MySQL驱动--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!--MP--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId></dependency><!--cloud-commons--><dependency><groupId>com.wbz</groupId><artifactId>cloud-commons</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>

新增的pom文件有OpenFeign的依赖和cloud-commons的依赖,并且因为OpenFeign也实现了负载均衡,所以要把父子均衡的依赖也加上去。

        <!--OpenFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--cloud-commons--><dependency><groupId>com.wbz</groupId><artifactId>cloud-commons</artifactId><version>1.0-SNAPSHOT</version></dependency>

写yml文件

server:port: 84spring:application:name: cloud-consumer-order-open-feign-84cloud:nacos:server-addr: 127.0.0.1:8848discovery:service: ${spring.application.name}config:prefix: ${spring.application.name}file-extension: ymlprofiles:active: devmvc:pathmatch:matching-strategy: ant_path_matcherdatasource:url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=trueusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus:configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/**Mapper.xmltype-aliases-package: com.wbz.domain

改主启动类

@MapperScan("com.wbz.mapper")
@SpringBootApplication
@EnableFeignClients // 服务调用
public class OpenFeignOrderConsumerApplication84 {public static void main(String[] args) {SpringApplication.run(OpenFeignOrderConsumerApplication84.class, args);}}

新增一个@EnableFeignClients注解用来开启服务调用。 

写业务类

// mapper接口
public interface OrderMapper extends BaseMapper<Order> {
}// service接口
public interface OrderService extends IService<Order> {Order getOrderById(Integer id);}// service实现类
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {@Resourceprivate ProductFeignApi productFeignApi;@Overridepublic Order getOrderById(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用Product product = this.productFeignApi.getProductById(order.getProductId());order.setProduct(product);// 返回结果return order;}}// controller实现类
@RestController
@RequestMapping("/order")
public class OrderController {@Resourceprivate OrderService orderService;@GetMapping("/query/{id}")public Order getOrderById(@PathVariable Integer id) {return this.orderService.getOrderById(id);}}

在上述的service实现类中可以看到,远程调用真的就像层与层之间的调用一样简单。

启动服务之后,输入127.0.0.1:84/product/query/1,出现下述结果就算成功:

 总结

到这里,使用OpenFeign进行远程调用的服务就搭建完成了。很容易能够看出,OpenFeign使用一行代码就实现了远程调用,所以相较于RestTemplate来说,更见简单方便。

在使用OpenFeign组件时,只需要引入对应依赖,然后在调用方使用@EnableFeignClients的注解,以及在客户端使用@FeignClient就能轻松解决问题。

OpenFeign参数传递

在OpenFeign的客户端接口中,进行参数绑定时不能省略,省略之后就会报错。

商品服务

@RestController
@RequestMapping("/product")
public class ProductController {@Resourceprivate ProductService productService;@GetMapping("/query/{productId}")public Product getProductById(@PathVariable Long productId) {return this.productService.getProductById(productId);}@GetMapping("/test1")public String test1(Long productId) {return "商品服务 - 测试传递单个参数成功";}@GetMapping("/test2")public String test2(Long productId, Long id) {return "商品服务 - 测试传递多个参数成功";}@GetMapping("/test3")public String test3(Order order) {return "商品服务 - 测试传递对象成功";}@PostMapping("/test4")public String test4(@RequestBody Order order) {return "商品服务 - 测试传递json成功";}}

cloud-commons

// 在OpenFeign中进行参数绑定时,不能省略。
@FeignClient(value = "cloud-provider-product-open-feign-8401", path = "/product")
public interface ProductFeignApi {// 传递URL上的参数@GetMapping("/query/{productId}")Product getProductById(@PathVariable("productId") Long productId);// 传递单个参数@GetMapping("/test1")String test1(@RequestParam("productId") Long productId);// 传递多个参数@GetMapping("/test2")String test2(@RequestParam("productId") Long productId,@RequestParam("id") Long id);// 传递对象@GetMapping("/test3")String test3(@SpringQueryMap Order order);// 传递json@PostMapping("/test4")String test4(@RequestBody Order order);}

订单服务

// controller类
@RestController
@RequestMapping("/order")
public class OrderController {@Resourceprivate OrderService orderService;@GetMapping("/query/{id}")public Order getOrderById(@PathVariable Integer id) {return this.orderService.getOrderById(id);}@GetMapping("/test1/{id}")public String test1(@PathVariable Integer id) {return this.orderService.test1(id);}@GetMapping("/test2/{id}")public String test2(@PathVariable Integer id) {return this.orderService.test2(id);}@GetMapping("/test3/{id}")public String test3(@PathVariable Integer id) {return this.orderService.test3(id);}@GetMapping("/test4/{id}")public String test4(@PathVariable Integer id) {return this.orderService.test4(id);}}// serive接口
public interface OrderService extends IService<Order> {Order getOrderById(Integer id);String test1(@PathVariable Integer id);String test2(@PathVariable Integer id);String test3(@PathVariable Integer id);String test4(@PathVariable Integer id);}// service实现类
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {@Resourceprivate ProductFeignApi productFeignApi;@Overridepublic Order getOrderById(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用Product product = this.productFeignApi.getProductById(order.getProductId());order.setProduct(product);// 返回结果return order;}@Overridepublic String test1(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用return this.productFeignApi.test1(order.getProductId());}@Overridepublic String test2(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用return this.productFeignApi.test2(order.getProductId(), order.getId());}@Overridepublic String test3(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用return this.productFeignApi.test3(order);}@Overridepublic String test4(Integer id) {// 获取订单Order order = this.getById(id);// 远程调用return this.productFeignApi.test4(order);}}

高级特性

大致原理

在OpenFeign组件中,主要使用的两个注解就是在启动类上的@EnableFeignClients注解以及在客户端接口上的@FeignClient注解。

首先,主启动类上的@EnableFeignClients注解开启对Feign接口代理对象的构建以及装配。在这个注解中,导入了一个FeignClientsRegistrar的类,这个类会扫描添加了FeignClient注解的接口,并且创建远程调用的对象,然后将该对象注入到Spring容器中。这样,在我们进行远程调用的代码就可以直接进行注入,并且对于注入的内容来说,会生产一个RequestTemplate的请求模板实例,在其中存储了请求路径、请求参数等内容。在请求调用时,会生成一个Request请求实例,然后根据Feign.Client的负载均衡实例,选择合适的服务进行调用。

这只是大概的过程,并且我也没有翻阅源码,在网上找的一段教程来看从而给出的方法。

@EnableFeignClients

basePackages表示扫描指定的包;

basePackageClasses表示扫描指定的类或接口对应的包;

defaultConfiguration表示自定义的FeignClient配置;

clients表示扫描指定的接口,配置之后,不会根据类路径进行扫描。

这几个定义扫描的都是用来查找FeignClient接口所在的位置,原因是因为如果cloud-commons的包结构和订单服务的包结构不相同的话,那么就无法进行扫描,所以就得自己配置扫描路径。

@FeignClient

value是用来定义服务名称,当多实例部署时,需要名称去拉取服务列表,然后再进行负载均衡,从而找到合适的服务。

url是用来给出服务地址,当只有一个服务时,直接给出URL,然后就可以进行调用。

fallback和fallbackFactory都是用来进行服务降级等功能的,后续在Sentinel中会进行介绍。

path是用来表示统一前缀的,例如都是商品服务中一个类下都是以product为前缀的,就可以直接放在path中,减少代码。

超时处理

在SpringCloud微服务架构中,大部分公司都是利用OpenFeign进行服务间的调用,而比较简单的业务使用默认配置是不会出现问题的,但是如果业务比较复杂,服务间要进行比较繁杂的业务计算,那后台很有可能会出现ReadException这个依次,因此就要定制化配置超时时间。

测试:首先在商品服务让其睡眠10秒,然后在订单服务中配置超时时间为3秒:

spring:application:name: cloud-consumer-order-open-feign-84cloud:nacos:server-addr: 127.0.0.1:8848discovery:service: ${spring.application.name}config:prefix: ${spring.application.name}file-extension: ymlopenfeign:client:config:default:#连接超时时间connectTimeout: 3000#读取超时时间readTimeout: 3000

项目启动之后,输入127.0.0.1:84/query/product/1,等待一段时间发现如下报错:

官方默认的等待时间为60秒钟,服务端超过规定时间就会导致Feign客户端返回报错。为了避免这样的情况,我们就需要设置Feign客户端的超时控制。

我们不仅可以控制所有的超时时间,还可以针对不同的服务来设置不同的超时时间:

spring:cloud:nacos:server-addr: 127.0.0.1:8848discovery:service: ${spring.application.name}config:prefix: ${spring.application.name}file-extension: ymlopenfeign:client:config:default:#连接超时时间connectTimeout: 3000#读取超时时间readTimeout: 3000# 配置商品服务的超时时间,会覆盖全局的默认时间cloud-provider-product-open-feign-8401:#连接超时时间connectTimeout: 3000#读取超时时间readTimeout: 3000

 重试机制

OpenFeign默认没有开重试机制,可以通过配置类开启:

@Configuration
public class FeignConfig {@Beanpublic Retryer retryer() {// 初识间隔时间为100毫秒// 重试间最大间隔时间为1秒// 最大请求次数为3次return new Retryer.Default(100, 1, 3);}}

为了测试,将订单服务中的代码进行如下修改:

项目启动之后,产生的日志为:

通过日志可以判断得出,我们添加的重试机制生效了。

请求/响应压缩

OpenFeign支持对请求/响应进行GZIP压缩,以减少通信过程中的性能损耗。

通过如下配置就可以实现相对应的压缩功能,并且还对请求压缩做了一些更细致的设置,比如下面的指定压缩数据类型以及指定触发压缩的大小。

spring:openfeign:client:config:default:#连接超时时间connectTimeout: 3000#读取超时时间readTimeout: 3000# 配置商品服务的超时时间,会覆盖全局的默认时间cloud-provider-product-open-feign-8401:#连接超时时间connectTimeout: 3000#读取超时时间readTimeout: 3000compression: # 压缩request:enabled: truemin-request-size: 2048 #最小触发压缩的大小mime-types: text/xml,application/xml,application/json #触发压缩数据类型response:enabled: true

日志打印功能

Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出。

Feign的日志级别有四种:

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:包含上述信息以及请求和响应的头信息;
  • FULL:包含上述信息以及请求和响应的正文及元数据。

想要开启日志打印功能,首先要进行配置类的配置,然后再写配置文件:

@Configuration
public class FeignConfig {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}}
logging:level:com:wbz:api:ProductFeignApi: debug
关键字:怎么制作自己的微信公众号_徐州网站建设策划_深圳百度推广公司_正规电商培训学校排名

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: