原先ribbon代码存在的问题:不规范,风格不统一,维护性比较差
什么是Feign
- SpringCloud提供的伪http客户端(本质还是用http),封装了Http调用流程,更适合面向接口化,用Java接口注解的方式调用Http请求
- 不用像Ribbon中通过封装HTTP请求报文的方式调用 Feign默认集成了Ribbon
- Nacos支持Feign,可以直接集成实现负载均衡的效果
Ribbon和feign两个的区别和选择
- 选择feign
- 默认集成了ribbon
- 写起来更加思路清晰和方便
- 采用注解方式进行配置,配置熔断等方式方便
官方文档
https://spring.io/projects/spring-cloud-openfeign
接入 Open-feign (相关代码完整版放在本文最后部分)
在之前章节的基础上,online-edu\pom.xml增加依赖:
<!-- 负载均衡-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>4.1.3</version>
</dependency>
online-edu-order-service/pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
online-edu-order-service/src/main/java/org/online_edu/OrderApplication.java
package org.online_edu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication()
@MapperScan("org.online_edu.dao")
// 开启服务发现
@EnableDiscoveryClient
// 开启openfeign负载均衡支持
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
online-edu-order-service/src/main/java/org/online_edu/controller/VideoOrderController.java
package org.online_edu.controller;
import org.online_edu.domain.Video;
import org.online_edu.domain.VideoOrder;
import org.online_edu.service.VideoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/api/v1/video_order")
public class VideoOrderController {
/**
* 服务对象
*/
@Autowired
private VideoService videoService;
@RequestMapping("/find_by_id")
public Object save(@RequestParam(name = "videoId") int videoId) {
Video video = videoService.findById(videoId);
VideoOrder videoOrder = new VideoOrder();
if (video != null) {
videoOrder.setServeInfo(video.getServeInfo());
videoOrder.setVideoId(video.getId());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setCreateTime(new Date());
}
return videoOrder;
}
}
online-edu-order-service/src/main/java/org/online_edu/service/VideoService.java
package org.online_edu.service;
import org.online_edu.domain.Video;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(value = "online-edu-video-service")
public interface VideoService {
@GetMapping(value = "/api/v1/video/find_by_id")
Video findById(@RequestParam("videoId") int videoId);
}
online-edu-video-service/src/main/java/org/online_edu/controller/VideoController.java
package org.online_edu.controller;
import jakarta.servlet.http.HttpServletRequest;
import org.online_edu.domain.Video;
import org.online_edu.service.VideoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api/v1/video")
public class VideoController {
@Autowired
private VideoService videoService;
@RequestMapping("/find_by_id")
public Video findById(@RequestParam(name = "videoId") int videoId, HttpServletRequest request) {
Video video = videoService.findById(videoId);
// 拿到服务端的id+端口
video.setServeInfo(request.getServerName() + ":" + request.getServerPort());
return video;
}
}
完整代码如下:
online-edu\pom.xml:
<?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>
<groupId>org.online_edu</groupId>
<artifactId>online-edu</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>online-edu-common</module>
<module>online-edu-video-service</module>
<module>online-edu-user-service</module>
<module>online-edu-order-service</module>
<module>online-edu-generator</module>
</modules>
<!-- 一般来说父级项目的packaging都为pom,packaging默认类型jar类型-->
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot-dependencies.version>3.3.3</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>2023.0.3</spring-cloud-dependencies.version>
<spring-cloud-alibaba-dependencies.version>2023.0.1.2</spring-cloud-alibaba-dependencies.version>
<org.mapstruct.version>1.6.0</org.mapstruct.version>
</properties>
<!--锁定版本-->
<dependencyManagement>
<dependencies>
<!-- **************************** 分布式核心 **************************** -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-alibaba-dependencies -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>4.1.4</version>
</dependency>
<!-- 负载均衡-openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>4.1.3</version>
</dependency>
<!-- **************************** 分布式核心 **************************** -->
<!-- **************************** 数据库依赖 **************************** -->
<!-- MyBatis-Plus启动器,增强版MyBatis,提供更高效的操作和动态SQL能力 -->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-spring-boot3-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generator -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.7</version>
</dependency>
<!-- PostgreSQL的JDBC驱动 -->
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.3</version>
</dependency>
<!-- Druid组件 -->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-3-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.23</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- **************************** 数据库依赖 **************************** -->
<!-- **************************** 工具类 **************************** -->
<!-- 一个用于在 Java Bean 之间转换的代码生成工具。-->
<!-- 官网:https://mapstruct.org/ -->
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct-processor -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- commons-lang3: 通用的、可复用的 Java 组件,已其他包引入-->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<!--(Map、List、Set集合全覆盖)集合开发工具-->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.5.0-M2</version>
</dependency>
<!-- Java增强器,像Java Next版本-->
<!-- 集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、
并发库 [concurrency libraries] 、通用注解 [common annotations] 、
字符串处理 [string processing] 、I/O 等等-->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.0-jre</version>
</dependency>
<!-- Java必备工具库 -->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.32</version>
</dependency>
<!-- JSON序列化和反序列化 :已由别的包引入-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<!-- **************************** 工具类 **************************** -->
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
online-edu-order-service/pom.xml
<?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>org.online_edu</groupId>
<artifactId>online-edu</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>online-edu-order-service</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.online_edu</groupId>
<artifactId>online-edu-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>-->
<!-- </dependency>-->
<!-- 添加nacos客户端——服务注册 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- PostgreSQL的JDBC驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
运行:
Post传输对象
online-edu-order-service/src/main/java/org/online_edu/controller/VideoOrderController.java
@PostMapping("/save")
public void save(@RequestBody Video video) {
videoService.save(video);
}
online-edu-order-service/src/main/java/org/online_edu/service/VideoService.java
@PostMapping(value = "/api/v1/video/save")
int save(@RequestBody Video video);
online-edu-video-service/src/main/java/org/online_edu/controller/VideoController.java
/**
* 测试 feign 调用 使用post方法传输对象
*
* @param video
* @return
*/
@PostMapping("/save")
public Object save(@RequestBody Video video) {
int rows = videoService.save(video);
System.out.println(video.getTitle());
HashMap<String, Object> map = new HashMap<>();
map.put("row", rows);
return map;
}
online-edu-video-service/src/main/java/org/online_edu/service/VideoService.java
int save(Video video);
online-edu-video-service/src/main/java/org/online_edu/service/impl/VideoServiceImpl.java
/**
* @param video
* @return
*/
@Override
public int save(Video video) {
return 1;
}
运行:
Header中的Content-Type
设置成application/json