在微服务架构中,由于业务功能的分工不同,我们把项目拆分为多个独立的服务,并常常将其部署在不同的服务器上,这个时候如果服务A的某个功能需要借助服务B来实现,那么这个时候如何去调用就成了问题,目前有一种常用的服务调用方法OpenFeign,用其可以实现服务之间的调用。
使用方法
1.原理
当一个服务通过openfeign向另一个服务发起远程调用时,feign会发起一个http请求,请求路径就是配置的url,服务A先将这个请求发往nacos,nacos根据服务发起者定义的服务目标名称寻找对应的服务,并将请求转发过去,并响应结果。
2.环境准备
我们要实现服务的调用,首先需要让他们之间互相能够发现彼此的存在,所以我们这里采用nacos作为服务的注册发现。
将服务A(serverA)和服务B(serverB)注册到nacos当中
在它们的pom文件中添加以下依赖(nacos当中若配置了其他的属性需要再添加如nacos-config等依赖)
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3.操作流程
假设我们需要让服务A调用服务B的某个方法,我们首先在服务A的pom文件中添加如下依赖
<!-- Spring Cloud 微服务远程调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</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>
以下是实现远程调用的一个样例
假设我们的需要调用服务B的接口方法是这样的
public class ServerBController {
@Autowired
ServerBService serverBservice;
@RequestMapping(value = "/media/upload/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALU)
public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile multipartFile,
@RequestParam(value= "objectName",required=false) String objectName) throws IOException {
//文件信息
UploadFileParamDto uploadFileParamDto = new UploadFileParamDto();
//原始文件名称
uploadFileParamDto.setFilename(multipartFile.getOriginalFilename());
//文件大小
uploadFileParamDto.setFileSize(multipartFile.getSize());
//文件类型
uploadFileParamDto.setFileType("001001");
//获取文件
File TempFile = File.createTempFile("md5", ".temp");
multipartFile.transferTo(TempFile);
Long companyId = 1L;
//文件路径
String absolutePath = TempFile.getAbsolutePath();
//上传图片
return mediaFileService.uploadMediaFile(companyId,uploadFileParamDto,absolutePath,objectName);
}
}
我们在服务A的类路径下创建一个包“feignClient”,在其下面创建一个远程调用接口ServerBClient
//这里为可选项,配置文件为你想要实现的功能 //fallback逻辑(可选)
@FeignClient(value = "ServerB",configuration = MultipartSupportConfig.class,fallbackFactory = MediaServiceClientFallbackFactory.class)
public interface ServerBClient {
//这里要和被调用处的接口路径保持一致
@RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String upload(@RequestPart("filedata") MultipartFile upload,@RequestParam(value = "objectName",required=false) String objectName);
}
注意在这个接口中的抽象类需要和被调用处的方法的请求方式、请求路径、参数都要保持一致
在FeignClient中定义的configuration和fallbackFactory需要自己定义,可以先删掉不写
在服务A的启动类上加上这个注解,表示启动服务远程调用
//将其中的包路径替换为你的包路径
@EnableFeignClients(basePackages={"com.enjoylearning.content.feignClient"})
这个时候我们启动服务A和服务B,让其在nacos中的服务列表中出现。
假设我们在服务A的Service层中需要调用服务B的这个方法,那么我们应该这样调用
@Service
public class ServiceAServiceImpl implements ServiceAService {
@Autowired
private ServerBClient serverBClient; //将远程调用接口注入
@Override
private void yourFunction(){
// ... 你的业务逻辑
//这里通过注入的feignClient接口调用服务B的upload方法
serverBClient.upload(参数A,参数B);
// ... 你的业务逻辑
}
}
最后服务A将能够正常的调用服务B的方法。
对于configuration和fallback等内容,我将在后续的篇幅中进行讲解使用方式和原理