导读:通过前面两篇文章我们准备好了微服务的基础环境并让accout-service 和 product-service对外提供了增删改查的能力,本篇我们的内容是让order-service作为消费者远程调用accout-service和product-service的服务接口。

统一接口返回结构

在开始今天的正餐之前我们先把上篇文章中那个丑陋的接口返回给优化掉,让所有的接口都有统一的返回结构。

  • 建立公共模块cloud-common
  • 其他模块都引入cloud-common,修改pom文件,加入依赖
<dependency><groupId>com.jianzh5.cloud</groupId><artifactId>cloud-common</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

  • 建立接口返回的数据结构,这个数据结构大家可以根据自身项目情况统一即可
@Data
public class ResultData<T> {/** 结果状态 ,正常响应200,其他状态码都为失败*/private int status;private String message;private T data;private boolean success;private long timestamp ;... 提供一些静态方法 ...
}

  • 改造accout-serviceproduct-service 模块中controller层的返回结构,改造完的代码如下:
@RestController
@Log4j2
public class AccountController {@Autowiredprivate AccountService accountService;@PostMapping("/account/insert")public ResultData<String> insert(@RequestBody AccountDTO accountDTO){log.info("insert account:{}",accountDTO);accountService.insertAccount(accountDTO);return ResultData.success("insert account succeed");}@PostMapping("/account/delete")public ResultData<String> delete(@RequestParam String accountCode){log.info("delete account,accountCode is {}",accountCode);accountService.deleteAccount(accountCode);return ResultData.success("delete account succeed");}@PostMapping("/account/update")public  ResultData<String> update(@RequestBody AccountDTO accountDTO){log.info("update account:{}",accountDTO);accountService.updateAccount(accountDTO);return ResultData.success("update account succeed");}@GetMapping("/account/getByCode/{accountCode}")public ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode){log.info("get account detail,accountCode is :{}",accountCode);AccountDTO accountDTO = accountService.selectByCode(accountCode);return ResultData.success(accountDTO);}
}

服务调用

SpringCloud体系中,所有微服务间的通信都是通过Feign进行调用,Feign是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像使用HttpClientOKHttp3等组件通过封装HTTP请求报文的方式调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。而且Feign默认集成了负载均衡器Ribbon,不需要自己实现负载均衡逻辑。

FeignSpringCloud的组件,在引入Feign之前我们先看看Spring BootSpring CloudSpring Cloud Alibaba 三者之间的关系,防止在业务中引入了错误的版本。

很显然,我们引用的是SpringCloud Alibab 0.9.0,所以我们需要引入SpringCloud Greenwich

  • 引入SpringCloud版本依赖
    在项目主pom <dependencyManagement>中引入SpringCloud依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Greenwich.SR2</version><type>pom</type><scope>import</scope>
</dependency>

  • 在所有需要用到Feign的模块中引入openfeign依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  • 抽取公共的接口层,建立Feign接口,接口的定义和返回值需要跟Controller层保持一致
@FeignClient(name = "account-service")
public interface AccountFeign {@PostMapping("/account/insert")ResultData<String> insert(@RequestBody AccountDTO accountDTO);@PostMapping("/account/delete")ResultData<String> delete(@RequestParam("accountCode") String accountCode);@PostMapping("/account/update")ResultData<String> update(@RequestBody AccountDTO accountDTO);@GetMapping("/account/getByCode/{accountCode}")ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode);
}

在接口上添加注解@FeignClient(name = "account-service"),表明这是一个Feign客户端,name属性的配置表示我这个接口最终会转发到accout-service上。

正如回字有多种写法,这里Feign也有多种使用方式。

第一种就是我们这里介绍的,Feign和生产者的RequestMapping保持一致,大家可以看看上面改造后的AccountControllerAccountFeign一模一样有米有。

第二种方式就是让我们的Controller直接实现Feign接口,不再需要写RequestMapping,如:

@RestController
@Log4j2
public class ProductController implements ProductFeign {@Autowiredprivate ProductService productService;@Overridepublic ResultData<String> insert(@RequestBody ProductDTO productDTO){log.info("insert product:{}",productDTO);productService.insertProduct(productDTO);return ResultData.success("insert product succeed");}
}

  • 消费者模块引入Feign接口层的依赖
<dependency><groupId>com.jianzh5.cloud</groupId><artifactId>account-feign</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

  • 在消费者product-service启动类上添加@EnableFeignClients注解
@SpringBootApplication
@RestController
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.javadaily.feign.*")
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

  • 消费者端跟使用本地service一样使用Feign
@RestController
public class OrderController {@Autowiredprivate AccountFeign accountFeign;@Autowiredprivate ProductFeign productFeign;@PostMapping("/order/getAccount/{accountCode}")public ResultData<AccountDTO> getAccount(@PathVariable String accountCode){return accountFeign.getByCode(accountCode);}@PostMapping("/order/insertAccount")public ResultData<String> insertAccount(AccountDTO accountDTO){return accountFeign.insert(accountDTO);}@PostMapping("/order/updateAccount")public ResultData<String> updateAccount(AccountDTO accountDTO){return accountFeign.update(accountDTO);}@PostMapping("/order/deleteAccount/{accountCode}")public ResultData<String> deleteAccount(@PathVariable String accountCode){return accountFeign.delete(accountCode);}
}

  • 项目模块截图
  • 联调测试
    我们请求OrderController中的接口,验证下接口请求结果:

联调成功,搞定收工!

血与泪

使用feign过程中有以下几点需要注意,否则一不小心你就会掉进坑里。(我不会告诉你我当时在坑里踩了多久才爬上来)

  • Feign不支持直接使用对象作为参数请求接口中如果有多参数需要用实体接收,要么把参数一个一个摆开,要么在对象参数上加上@RequestBody注解,让其以json方式接收,如:
@PostMapping("/account/insert")ResultData<String> insert(@RequestBody AccountDTO accountDTO);

  • 消费者模块启动类上使用@EnableFeignClients注解后一定要指明Feign接口所在的包路径如:@EnableFeignClients(basePackages = "com.javadaily.feign.*")否则你的消费者启动时会报如下的错误:

所以这里推荐你们在开发中所有feign模块最好能统一包名前缀com.javadaily.feign

  • @RequestParam的坑在Feign接口层使用@RequestParam注解要注意,一定要加上value属性,如:ResultData<String> delete(@RequestParam("accountCode") String accountCode);否则你会看到类似如下的错误:Caused by: java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0这个异常
  • @PathVariable的坑在Feign接口层使用@PathVariable注解要注意,一定要跟上面一样加上value属性,如:ResultData<AccountDTO> getByCode(@PathVariable(value = "accountCode") String accountCode);否则你也会看到类似如下的错误@PathVariable(value = "accountCode") String accountCode
  • 在消费者配置文件中添加Feign超时时间配置在我们的order-service配置文件中增加feign超时时间配置
feign:client:config:default:connectTimeout: 5000readTimeout: 5000

否则你会经常看到如下所示的错误:

java.net.SocketTimeoutException: Read timed outat java.net.SocketInputStream.socketRead0(Native Method) ~[?:1.8.0_112]

至此我们已经完成了项目公共返回接口的统一并且成功使用Feign调用远程生产者的服务,那么本期的“SpringCloud Alibaba微服务实战三 - 服务调用”篇也就该结束啦,咱们下期有缘再见!

系列文章

  • SpringCloud Alibaba微服务实战一 - 基础环境准备
  • SpringCloud Alibaba微服务实战二 - 服务注册

controller调用controller的方法_SpringCloud Alibaba微服务实战三 - 服务调用相关推荐

  1. SpringCloud Alibaba微服务实战三 - 服务调用

    SpringCloud Alibaba微服务实战三 - 服务调用 通过前面两篇文章我们准备好了微服务的基础环境并运行注册服务到nacos上了 统一接口返回结构 在开始今天的正餐之前我们先把上篇文章中那 ...

  2. java 限流熔断_SpringCloud Alibaba微服务实战五 - 限流熔断

    简介 Sentinel是面向分布式服务框架的轻量级流量控制框架,主要以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度来维护系统的稳定性.在SpringCloud体系中,sentinel主要 ...

  3. SpringCloud Alibaba微服务实战(三) - Nacos服务创建消费者(Feign)

    什么是Feign Feign 是一个声明式的伪 Http 客户端,它使得写 Http 客户端变得更简单.使用 Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用 Feign 注解和 ...

  4. SpringCloud Alibaba微服务实战(五) - Sentinel实现限流熔断

    什么是Sentinel? 请查看文章:SpringCloud Alibaba微服务实战(一) - 基础环境搭建 构建服务消费者cloud-sentinel进行服务调用 服务创建请查看文章:Spring ...

  5. SpringCloud Alibaba微服务实战(七) - 路由网关(Gateway)全局过滤

    说在前面 全局过滤器作用于所有的路由,不需要单独配置,我们可以用它来实现很多统一化处理的业务需求,比如权限认证,IP 访问限制,监控,限流等等. 创建路由网关(Gateway)启动服务cloud-ac ...

  6. SpringCloud Alibaba微服务实战(四) - Nacos Config 配置中心

    说在前面 Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台.Nacos Config就是一个类似于SpringCloud Config的配置中心. 一.启动N ...

  7. go语言高并发与微服务实战_go-micro+gin+etcd微服务实战之服务注册与发现

    在构建微服务时,使用服务发现可以减少配置的复杂性,本文以go-micro为微服务框架,使用etcd作为服务发现服务,使用gin开发golang服务. 使用gin 的原因是gin能够很好的和go-mic ...

  8. SpringCloud Alibaba微服务实战(二) - Nacos服务注册与restTemplate消费

    说在前面 基础环境搭建,理论,请看上一篇,在这就不扯理论了,直接上代码. 项目结构 代码实现 第一步:在父pom的项目中引入dependencyManagement 在引入父pom之前咱们先来回顾下d ...

  9. SpringCloud Alibaba微服务实战(一) - 基础环境搭建

    说在前面 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案.此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来 ...

最新文章

  1. python浪漫表白代码
  2. 计算机网络谢希仁第七版课后答案第二章 物理层
  3. 个人日记2016年12月19日21:31:46
  4. linux deepin “debconf: DbDriver “config“: config.dat 被另一个进程锁定:资源暂时不可用“
  5. python定义函数计算斐波那契公式前20的项_Python3算法之二:斐波那契函数
  6. maven依赖,聚合和继承
  7. 并发执行变成串行_网易Java研发面试官眼中的Java并发——安全性、活跃性、性能...
  8. 动态生成的html元素无法调用js函数,如何确保动态生成的div在js函数被调用之前被加载到DOM中?...
  9. java三国群雄_三国群英-真三国无双
  10. Linux下KDE桌面系统快捷键
  11. 移动端常用Axure组件库 元件库下载 包含微信 支付宝常用组件元素
  12. php安装ziparchive扩展,记一次PHP扩展-ZipArchive安装
  13. html如何将设置文本效果,Word2013中通过设置文本效果格式来为文字添加特殊效果...
  14. 有向图的拓扑排序算法JAVA实现。
  15. 前端实现压缩图片的功能(vue-element)
  16. chrome绿色版浏览器
  17. Android中 .stub类的使用
  18. AEM CV100 多功能线缆测试仪可以做什么?
  19. 201671030123叶虹《英文文本统计分析》结对项目报告
  20. 射频测试 —— 蓝牙定频测试1

热门文章

  1. Oracle 记录插入时“Invalid parameter binding ”错误
  2. Android驱动开发读书笔记六
  3. Android的内存优化
  4. PHP文件打包类和实例
  5. c++ builder 读取指定单个名称节点的值
  6. Linux磁盘占用100%解决方法
  7. ViewBag与ViewData传值乱码问题解决方案
  8. Maven项目配置EL表达式原样输出解决方法
  9. 解决WAS报错SRVE0207E: servlet 创建了未捕获到的初始化异常
  10. 解决iOS微信H5支付跳转微信后不返回App问题(Swift-WKWebview)(转)