文章目录
- 一、前提条件和背景
- 1. 前提
- 2. 背景
- 二、Feign模块
- 1. 依赖引入
- 2. `application.yaml`配置
- 3. 扩展支持MultipartFile
- 4. 将media-api注册到feign
- 三、Media模块
- 四、Content模块
- 1. 引入依赖
- 2. 启用FeignClient
- 3. 测试
- 五、需要澄清的几点
一、前提条件和背景
1. 前提
已经部署好Nacos,本文以192.168.101.65:8848
为例。
2. 背景
有两个微服务media
和content
,都已经注册到Nacos
。
后者通过引用Feign
实现远程调用前者。
两个微服务都被分为3个子模块:api、service、model
,对应三层架构。
请根据自身情况出发阅读本文。
二、Feign模块
1. 依赖引入
首先需要Feign
依赖和扩展。
<!-- 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><version>4.1.0</version></dependency><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency><!--feign支持Multipart格式传参--><dependency><groupId>io.github.openfeign.form</groupId><artifactId>feign-form</artifactId><version>3.8.0</version></dependency><dependency><groupId>io.github.openfeign.form</groupId><artifactId>feign-form-spring</artifactId><version>3.8.0</version></dependency>
需要测试
依赖(可选),为了MockMultipartFile
类才引入的,非必需功能。
<!-- 测试 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.1.2</version><scope>compile</scope>
</dependency>
其次需要涉及到的微服务的数据模型,根据个人情况而定。
如果只想要它们的数据模型,而不引入不必要的依赖,可以使用通配符*全部过滤掉。
<!-- 数据模型pojo --><dependency><groupId>com.xuecheng</groupId><artifactId>xuecheng-plus-media-model</artifactId><version>0.0.1-SNAPSHOT</version><exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.xuecheng</groupId><artifactId>xuecheng-plus-content-model</artifactId><version>0.0.1-SNAPSHOT</version><exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency>
2. application.yaml
配置
填入以下内容,大抵为超时熔断处理。(可选),甚至可以留空。
feign:hystrix:enabled: truecircuitbreaker:enabled: true
hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 30000
ribbon:ConnectTimeout: 60000ReadTimeout: 60000MaxAutoRetries: 0MaxAutoRetriesNextServer: 1
3. 扩展支持MultipartFile
新建一个配置类,如下,
主要是Encoder feignEncoder()
使得Feign
支持MultipartFile
类型传输。
MultipartFile getMultipartFile(File file)
是一个工具方法,和配置无关。
@Configuration
public class MultipartSupportConfig {@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Bean@Primary//注入相同类型的bean时优先使用@Scope("prototype")public Encoder feignEncoder() {return new SpringFormEncoder(new SpringEncoder(messageConverters));}//将file转为Multipartpublic static MultipartFile getMultipartFile(File file) {try {byte[] content = Files.readAllBytes(file.toPath());MultipartFile multipartFile = new MockMultipartFile(file.getName(),file.getName(), Files.probeContentType(file.toPath()), content);return multipartFile;} catch (IOException e) {e.printStackTrace();XueChengPlusException.cast("File->MultipartFile转化失败");return null;}}
}
4. 将media-api注册到feign
新建一个类,如下。
@FeignClient(value)
要和服务名称对上,即media
模块spring.application.name=media-api
。
@FeignClient(path)
要和服务前缀路径对上,即media
模块server.servlet.context-path=/media
。
然后MediaClient
中的方法定义尽量和media
模块对应的controller
函数保持一致。
@FeignClient(value = "media-api", path = "/media")
public interface MediaClient {@RequestMapping(value = "/upload/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile file,@RequestParam(value = "objectName", required = false) String objectName);
}
三、Media模块
被调用方media
模块无需做什么修改。
四、Content模块
测试在content-api
上操作。
1. 引入依赖
content模块需要引入刚才feign模块的依赖。
<dependency><!-- 根据自身情况引入 -->
</dependency>
2. 启用FeignClient
在启动类上加上@EnableFeignClients
注解。
3. 测试
新建测试类,如下
package com.xuecheng.content.service.jobhandler;import com.xuecheng.feign.client.MediaClient;
import com.xuecheng.media.model.dto.UploadFileResultDto;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;@SpringBootTest
class CoursePublishTaskTest {@AutowiredMediaClient mediaClient;@Testvoid generateCourseHtml() {MultipartFile file = new MockMultipartFile("filedata","filename.txt","text/plain","Some dataset...".getBytes());UploadFileResultDto upload = mediaClient.upload(file, "/static-test/t-1");System.out.println(upload);}
}
启动Media
模块,启动测试方法,
具体的Debug和检验,可以通过Media
模块对应的controller
函数打印日志,检查是否通过MediaClient
被触发。
五、需要澄清的几点
-
Feign模块不需要注册到Nacos且不需要服务发现:
正确。feign-client
模块只是一个包含Feign客户端接口的库,它自身并不是一个独立的微服务。因此,它不需要注册到Nacos,也不需要服务发现功能。这个模块只是被其他微服务模块(如content
模块)作为依赖引入。这样做的主要目的是为了代码的重用和解耦,允许任何微服务通过引入这个依赖来调用其他服务。 -
只有调用者(如
content
模块)需要使用@EnableFeignClients
注解,被调用者(如media
模块)不需要:
正确。@EnableFeignClients
注解是用来启用Feign客户端的,它告诉Spring Cloud这个服务将会使用Feign来进行远程服务调用。因此,只有需要使用Feign客户端的服务(在这个例子中是content
模块)需要添加这个注解。而被调用的服务(如media
模块),只需作为普通的Spring Boot应用运行,提供REST API即可,无需使用@EnableFeignClients
。 -
如何在服务间共享数据模型(如DTOs)而不引入不必要的依赖。
解决这个问题的一种方法是创建一个共享的库或模块,这个库包含所有服务共享的数据模型。另一种使用依赖剥离,使用通配符(*)可以排除pom.xml
中特定依赖的所有传递性依赖。