前言

在开发SpringCloud应用中,Feign作为声明式调用的事实标准极大的简化了Rest远程调用,提供了类本地化的调用方式。服务提供方的接口暴露方式是通过Controller暴露Restful,而在这个Controller的代码现实中大部分都是处理请求然后再调用Service中的方法,是一个比较模板化的功能,但是工作量确不少。本文介绍一种通过动态代理的方式无需Controller直接暴露Restful接口。
本文中使用笔者在Github开源的框架来实现,本文的讲解也在这个框架基础之上来说明
Git路径:https://github.com/leecho/spr...

依赖

     <dependency><groupId>com.github.leecho</groupId><artifactId>spring-cloud-starter-feign-proxy</artifactId><version>{last-version}</version></dependency>

实现

定义Service Interface

首先定义服务接口,使用@FeignClient标示是一个Feign接口,在这个示例Sevice中定义了CURD和文件上传方法,并使用了一些常用参数注解

@Api(tags = "DemoService", description = "Demo Feign Client")
@FeignClient("demo-service")
public interface DemoService {/*** create demo** @param demo* @return*/@ApiOperation(value = "Create demo")@PostMapping(value = "/demo")Demo create(@RequestBody @Valid @ApiParam Demo demo);/*** update demo** @param demo* @return*/@PutMapping(value = "/demo")Demo update(@RequestBody @Valid Demo demo);/*** delete demo** @param id* @return*/@DeleteMapping(value = "/demo/{id}")Demo delete(@PathVariable(name = "id") String id);/*** list demo** @param id* @param headerValue test header value* @return*/@GetMapping(value = "/demo/{id}")Demo get(@PathVariable(name = "id") String id, @RequestHeader(name = "header") String headerValue);/*** list demos** @return*/@GetMapping(value = "/demos")List<Demo> list();/*** upload file** @param file* @return*/@PostMapping(value = "/demo/upload")String upload(@RequestPart(name = "file") MultipartFile file);
}

实现Service

在实现类中简单的实现了CURD和上传文件的方法

@Slf4j
@Primary
@Service
public class DemoServiceImpl implements DemoService {@Overridepublic Demo create(Demo demo) {log.info("Create executed : " + demo);return demo;}@Overridepublic Demo update(Demo demo) {log.info("Update execute :" + demo);return demo;}@Overridepublic Demo delete(String id) {log.info("Delete execute : " + id);return Demo.builder().name("demo-" + id).data("data-" + id).build();}@Overridepublic Demo get(String id, String header) {Demo demo = Demo.builder().name(header).data(header).build();System.out.println("Get execute : " + id + "," + header);return demo;}@Overridepublic List<Demo> list() {System.out.println("List execute");List<Demo> demos = new ArrayList<>();for (int i = 0; i < 5; i++) {Demo demo = Demo.builder().name("demo-" + i).data("data" + i).build();demos.add(demo);}return demos;}@Overridepublic String upload(MultipartFile file) {return file.getOriginalFilename();}
}

动态生成Restful接口的原理是动态生成Controller类实现ServiceInterface,如果真正的实现类会被其他BEAN依赖,需要通过注解@Primary来方式来防止依赖冲突

配置应用

在应用中通过@EnableFeignProxies来标示应用在启动的过程中会扫描所有的FeignClients并暴露Restful接口

@EnableFeignProxies(basePackages = "com.github.leecho")
@ComponentScan("com.github.leecho")
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}

测试用例

在测试用例中对Service的接口进行测试

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class DemoApplicationTest {@Autowiredprivate WebApplicationContext context;private MockMvc mvc;@Beforepublic void setUp() {mvc = MockMvcBuilders.webAppContextSetup(context).build();}@Testpublic void create() throws Exception {mvc.perform(MockMvcRequestBuilders.post("/demo").contentType(MediaType.APPLICATION_JSON_UTF8).content(new ObjectMapper().writeValueAsString(Demo.builder().name("create").data("data").build())).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void update() throws Exception {mvc.perform(MockMvcRequestBuilders.put("/demo").contentType(MediaType.APPLICATION_JSON_UTF8).content(new ObjectMapper().writeValueAsString(Demo.builder().name("update").data("data").build())).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void delete() throws Exception {mvc.perform(MockMvcRequestBuilders.delete("/demo/{id}", "1").contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void get() throws Exception {mvc.perform(MockMvcRequestBuilders.get("/demo/{id}", "1").contentType(MediaType.APPLICATION_JSON_UTF8).header("header", "header-value").accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void list() throws Exception {mvc.perform(MockMvcRequestBuilders.get("/demos").contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}@Testpublic void upload() throws Exception {mvc.perform(MockMvcRequestBuilders.multipart("/demo/upload").file(new MockMultipartFile("file", "test.txt", ",multipart/form-data", "upload test".getBytes())).accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()).andDo(MockMvcResultHandlers.print());}
}

在启动日志中也可以看到Restful接口已经暴露成功。

后语

关于这个框架的介绍,后续详细的给大家进行介绍。文中所涉及到的代码也在Git中:spring-cloud-feign-proxy-sample

Spring Cloud Feign Clients 无需 Controller自动暴露Restful接口相关推荐

  1. Spring Cloud的负载均衡Spring Cloud Ribbon和Spring Cloud Feign

    一.客户端负载均衡:Spring Cloud Ribbon. Spring Cloud Ribbon是基于HTTP和TCP的客户端负载工具,它是基于Netflix Ribbon实现的.通过Spring ...

  2. Spring Cloud Feign使用详解

     通过前面两章对Spring Cloud Ribbon和Spring Cloud Hystrix的介绍,我们已经掌握了开发微服务应用时,两个重要武器,学会了如何在微服务架构中实现客户端负载均衡的服务调 ...

  3. Spring Cloud Feign传输Header,并保证多线程情况下也适用

    Spring Cloud Feign传输Header,并保证多线程情况下也适用 一.现象 微服务在生产中,常遇到需要把 header 传递到下一子服务的情况(如服务A访问服务B的接口,需要传递head ...

  4. Spring Cloud Feign原理详解

    目录 1.什么是Feign? 2.Open Feign vs Spring Cloud Feign 2.1.OpenFeign 2.2.Spring Cloud Open Feign 3.Spring ...

  5. Spring Cloud Feign - 内部实现细节

    1. 概述 Feign用于服务间调用,它的内部实现是一个包含Ribbon(负载均衡)的JDK-HttpURLConnection(Http)调用.虽然调用形式是类似于RPC,但是实际调用是Http,这 ...

  6. Spring Cloud Feign 请求压缩 、Feign的日志级别配置

    一.Spring Cloud Feign 请求压缩 #开启压缩compression:request:enabled: true # 开启请求压缩#最小触发压缩的大小min-request-size: ...

  7. k8s springboot 文件_Springboot整合Spring Cloud Kubernetes读取ConfigMap支持自动刷新配置的教程...

    1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! Docker & Kubernetes相关文章:容器技术 之前介绍了Spring Cloud Config的用法,但 ...

  8. Spring Cloud Feign 1(声明式服务调用Feign 简介)

    Spring Cloud Feign基于Netflix Feign 同时整合了Spring Cloud Ribbon和Spring Cloud Hytrix,除了提供两者的强大功能外,它还提供了一种声 ...

  9. Spring Cloud Feign 请求时附带请求头

    Spring Cloud Feign 请求时附带请求头 问题描述 解决方案 FeignConfiguration 使用 配置修改 问题描述 Feign 在请求时是不会将 request 的请求头带着请 ...

最新文章

  1. 根据DNS的A记录负载均衡web服务请求
  2. 成功解决ValueError: setting an array element with a sequence.
  3. [你必须知道的.NET] 第二回:对抽象编程:接口和抽象类
  4. 美团客户端响应式框架 EasyReact 开源啦
  5. 当你输入一个网址的时候,实际会发生什么?(转)
  6. Awesome Go
  7. 普通类创建获取session 方式_Springboot系列之RestApi中获取枚举类属性的几种方式...
  8. 如何为自定义的控件在工具箱中自定义个性化的图标
  9. 一个月的java工作总结
  10. 误删MySQL数据库中的mysql库怎么恢复
  11. 51单片机 驱动有源/无源蜂鸣器+Proteus仿真
  12. Linux编程基础期末冲刺——第3章用户组与用户组管理
  13. hdu 3987 - 最小割最少割边
  14. OAuth2授权原理
  15. 2019年终总结2020个人规划和目标
  16. 《Word中从正文开始设置页码》
  17. 苹果vs剪辑下载_Vlog教程 | 如何在手机剪辑app中添加自己的音乐?
  18. RAR Extractor - The Unarchiver Pro for mac(解压缩软件)
  19. mysql如何不停机迁移_如何实现真正的不停机数据迁移?
  20. 青春三部曲(《且听风吟》,《一九七三年的弹子球》,《寻羊冒险记》)--[日]村上春树...

热门文章

  1. TCP/IP,Http,Socket的区别
  2. CSS里常见的块级元素和行内元素
  3. 团队-象棋游戏-开发文档
  4. maven(5)--依赖特性
  5. jsp页面中静态文件的时间戳
  6. [cb]NGUI组件基类之 UIWidget
  7. Eclipse ADT 21 Preview 10 发布
  8. VSC 1.0 (netapp存储在vSphere vCenter 4上的插件)
  9. linux下mysql修改root密码
  10. C语言初学者简单语法综合练习