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

JAVA日知录 一个关注| Java | Spring Boot | Spring Cloud | 干货分享的博客网站 本文由博客端 http://www.javadaily.cn 主动推送
本贴最后更新于 721 天前,其中的信息可能已经沧海桑田

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

统一接口返回结构

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

<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 ;
	
    ... 提供一些静态方法 ...
}
@RestController
@Log4j2
public class AccountController {
    @Autowired
    private 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 三者之间的关系,防止在业务中引入了错误的版本。

Spring Boot Spring Cloud Spring Cloud Alibaba
2.1.x Greenwich 0.9.x
2.0.x Finchley 0.2.x
1.5.x Edgware 0.1.x
1.5.x Dalston 0.1.x
很显然,我们引用的是 SpringCloud Alibab 0.9.0,所以我们需要引入 SpringCloud Greenwich
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-dependencies</artifactId>
	<version>Greenwich.SR2</version>
	<type>pom</type>
	<scope>import</scope>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@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 {
    @Autowired
    private ProductService productService;

    @Override
    public ResultData<String> insert(@RequestBody ProductDTO productDTO){
        log.info("insert product:{}",productDTO);
        productService.insertProduct(productDTO);
        return ResultData.success("insert product succeed");
    }
}
<dependency>
	<groupId>com.jianzh5.cloud</groupId>
	<artifactId>account-feign</artifactId>
	<version>1.0-SNAPSHOT</version>
</dependency>
@SpringBootApplication
@RestController
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.javadaily.feign.*")
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
@RestController
public class OrderController {
    @Autowired
    private AccountFeign accountFeign;

    @Autowired
    private 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);
    }
}

血与泪

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

@PostMapping("/account/insert")ResultData<String> insert(@RequestBody AccountDTO accountDTO);
feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

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

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

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

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    895 引用 • 1443 回帖 • 559 关注
  • 云计算
    76 引用 • 91 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    86 引用 • 155 回帖
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    133 引用 • 440 回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • jianzh5
    作者

    可以关注我公众号啊,javadaily

  • 其他回帖
  • sgkt

    没有源码可以看看吗?

    怎么感觉 dto 在每个工程都有依赖

    1 回复