SpringCloud微服务使用Feign如何暴露接口并整合SpringBoot测试
文章目录一. 问题背景二. 解决方案2.1 实现生产者中的接口2.2 暴露接口2.3 远程调用2.4 SpringBoot整合测试2.5 开始测试一. 问题背景技术栈:SpringBoot+SpringCloud项目结构组织:项目由多个Module构成,而每个Module又由api模块、model模块、web模块构成需求:现在需要将A项目(生产者,或者叫服务提供者)的web模块中的某些接口暴露出去
一. 问题背景
技术栈:SpringBoot+SpringCloud
项目结构组织:项目由多个Module构成,而每个Module又由api模块、model模块、web模块构成
需求:现在需要将A项目(生产者,或者叫服务提供者)的web模块中的某些接口暴露出去,要求在api模块中定义。使得B项目(消费者,或者叫客户端)能远程调用A项目暴露的接口
备注:笔者对SpringCloud只有了解并未实践过,导致实现这个需求时踩了不少坑,本博客适合初次实操SpringCloud或者如何暴露接口的小白。
解决踩坑过程中觉得不错的博客:【SpringCloud】 - Feign 踩坑记录:404 ,调用不成功 , 接口定义规范 等问题记录
二. 解决方案
这里先给出代码实现以及注意事项,后面有时间再补充微服务相关的知识。
2.1 实现生产者中的接口
- 首先实现生产者中的接口,在A项目的web模块中,代码如下:
@Api(value = "字典定义", tags = " 字典定义")
@RestController
@RequestMapping(value = "/wcenter/dict/define")
public class WcenterDictDefineRest {
/**
* 获取树状字典
**/
@ApiOperation(value = "获取树状字典")
@ApiImplicitParams({
@ApiImplicitParam(name = "codes", value = "字典编码", paramType = "query", dataType = "String[]"),
})
@GetMapping(value = "/tree")
public ResponsePacket<ResponseTreeEntityDto> tree(HttpServletRequest request, String[] codes) {
//...业务逻辑
return xxx;
}
}
注意:上面那个类,必须加@RestController注解,否则后面调用api模块暴露的接口会出现问题。
2.2 暴露接口
- 首先要引入Feign的依赖,Feign依赖是必须引入的,其余依赖根据自己的接口需要引入其他依赖。如下:
<!-- Feign Form Spring -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version>
</dependency>
<!-- Feign Form -->
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
<!-- Feign Core-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>10.10.1</version>
</dependency>
<!-- Feign Hystrix -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
<version>10.10.1</version>
</dependency>
<!-- Feign Slf4j -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>10.10.1</version>
</dependency>
- 暴露接口,在A项目的api模块中,代码如下:
@Api("数据字典远程服务接口")
@FeignClient(value = "接口的实现方法所在项目的微服务名", path = "web以及请求路径")
public interface DictFeign {
@ApiOperation(value = "获取树状字典")
@ApiImplicitParams({
@ApiImplicitParam(name = "codes", value = "字典编码", paramType = "query", dataType = "String[]"),
})
@GetMapping(value = "/tree")
ResponsePacket<ResponseTreeEntityDto> tree(@RequestParam("request") HttpServletRequest request, @RequestParam("codes") String[] codes);
}
注意:
- 必须加@FeignClient声明
- 其他 value属性的值是yml文件中
spring.application.name
的值,这里建议用全局变量来填写,方便管理更多的微服务 - 如果yml文件中配置了
server.servlet.context-path
,必须配上path属性。否则后面调用这个接口会出现404问题 - 关于方法的mapping注解,有人说Feign不支持 GetMapping,笔者测试过 是支持的。这应该与某些依赖的版本有关
- 方法参数必须加@RequestParam注解(否则,后面调用该接口会报
too many bad parameter
错误),若是POST请求方式,需要根据情况加@RequestBody注解
2.3 远程调用
- 需要在B项目中引入A项目的api模块的依赖,例子如下:
<dependency>
<groupId>xxx.xxx</groupId>
<artifactId>business-wcenter-api</artifactId>
<version>2.0.0</version>
</dependency>
- B项目的启动类必须加上@EnableFeignClients注解,还必须要加上basePackages的属性,他的值是标注了@FeignClient注解的接口的包路径,如下:
@EnableFeignClients(basePackages = "xx.xx.xx")
@SpringCloudApplication
public class CriterionServerApplication {
}
2.4 SpringBoot整合测试
引入SpringBoot的测试依赖,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
- 代码如下:
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(
classes = 启动类.class
)
public class DictFeignTest {
@Autowired
DictFeign dictFeign;
/**
* 测试 远程调用数据字典
*/
@Test
public void testRpcDictFeign(){
ResponsePacket<ResponseTreeEntityDto> tree = dictFeign.tree(null, null);
log.info("The dict tree is: {}", tree);
}
}
2.5 开始测试
这种暴露接口的测试,必须先启动生产者(服务提供者),再启动消费者(客户端)。
我们先启动A项目,再启动B项目,运行上面的测试方法,测试成功。
三. 回调处理
前面讲述了远程调用的简单版本,如果调用失败,是没有相应的机制去处理的,那么接下来就实现调用失败的处理机制,这里简称方法回调
代码如下:
@FeignClient(value = "xxx", path = "xxx", fallbackFactory = DictDefineFallbackFactory.class)
public interface DictDefineFeign {
}
解释:使用@FeignClient
注解的fallbackFactory
属性,其值是一个类,代码如下:
@Component
@Slf4j
public class DictDefineFallbackFactory implements FallbackFactory<DictDefineFeign> {
@Override
public DictDefineFeign create(Throwable throwable) {
log.error("字典定义服务调用失败:" + throwable.getMessage());
return new DictDefineFeign() {
@Override
public ResponsePacket<ResponseTreeEntityDto> tree(String[] codes) {
return ResponsePacket.generateFail("字典定义服务--->获取树状字典失败");
}
};
}
}
四. 踩坑记录
测试暴露接口的过程中,遇到了一系列形如“xxxClass can not find、xxxMethod is not define”
,一般都是对应的依赖没有下载下来。尤其是依赖中的依赖,有些是设置了<optional>true</optional>
,这个作用是只允许此依赖所在的项目使用,即使别的项目引用了这个依赖,都无法下载下来。
因此解决方法是调整依赖,或者单独引入缺失的依赖
更多推荐
所有评论(0)