「整合系列」服务调用(HTTP)


本篇我们的内容是让order-service作为消费者远程调用accout-service和product-service的服务接口。

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

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

1、在项目主pom 中引入SpringCloud依赖:



	org.springframework.cloud
	spring-cloud-dependencies
	Hoxton.SR9
	pom
	import

2、在order-biz下单独创建一个子模块order-feign,并引入openfeign依赖:


	org.springframework.cloud
	spring-cloud-starter-openfeign

order-feign项目模块截图:

AccountFeign类代码如下:

@FeignClient(name = "account-service")
public interface AccountFeign {

    @PostMapping("/account/insert")
    Result insert(@RequestBody AccountDTO accountDTO);

    @PostMapping("/account/delete")
    Result delete(@RequestParam("id") Long id);

    @PostMapping("/account/update")
    Result update(@RequestBody AccountDTO accountDTO);

    @GetMapping("/account/{id}")
    Result getById(@PathVariable(value = "id") Long id);
}

ProductFeign类代码如下:

@FeignClient(name = "product-service")
public interface ProductFeign {
    @PostMapping("/product/insert")
    Result insert(@RequestBody ProductDTO productDTO);

    @PostMapping("/product/delete")
    Result delete(@RequestParam("id") Long id);

    @PostMapping("/product/update")
    Result update(@RequestBody ProductDTO productDTO);

    @GetMapping("/product/{id}")
    Result getById(@PathVariable(value = "id") Long id);
}

AccountDTO和ProductDTO如下:

@Data
public class AccountDTO implements Serializable {
    private Long id;
    private String accountCode;
    private String accountName;
    private BigDecimal amount;
}

@Data
public class ProductDTO implements Serializable {
    private Long id;
    private String productCode;
    private String productName;
    private Integer count;
    private BigDecimal price;
}

3、在order-service模块中添加order-feign的依赖:


	order-feign
	com.harvey
	1.0-SNAPSHOT

启动类添加@EnableFeignClients注解:

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients(basePackages = {"com.harvey.feign.client"})
public class OrderApp {
    public static void main(String[] args) {
        SpringApplication.run(OrderApp.class, args);
    }
}

AccountFeignController类代码:

@RestController
public class AccountFeignController {

    @Autowired
    private AccountFeign accountFeign;

    @PostMapping("/account/insert")
    Result insert(@RequestBody AccountDTO accountDTO){
        return accountFeign.insert(accountDTO);
    }

    @PostMapping("/account/delete")
    Result delete(@RequestParam("id") Long id){
        return accountFeign.delete(id);
    }

    @PostMapping("/account/update")
    Result update(@RequestBody AccountDTO accountDTO){
        return accountFeign.update(accountDTO);
    }

    @GetMapping("/account/{id}")
    Result getById(@PathVariable(value = "id") Long id){
        return accountFeign.getById(id);
    }
}

ProductFeignController类代码如下:

@RestController
public class ProductFeignController {

    @Autowired
    private ProductFeign productFeign;

    @PostMapping("/product/insert")
    Result insert(@RequestBody ProductDTO productDTO){
        return productFeign.insert(productDTO);
    }

    @PostMapping("/product/delete")
    Result delete(@RequestParam("id") Long id){
        return productFeign.delete(id);
    }

    @PostMapping("/product/update")
    Result update(@RequestBody ProductDTO productDTO){
        return productFeign.update(productDTO);
    }

    @GetMapping("/product/{id}")
    Result getById(@PathVariable(value = "id") Long id){
        return productFeign.getById(id);
    }
}

application..yml添加超时时间:

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000

4、openfeign的注意事项

(1)Feign不支持直接使用对象作为参数请求

接口中如果有多参数需要用实体接收,要么把参数一个一个摆开,要么在对象参数上加上@RequestBody注解,让其以json方式接收,如:

@PostMapping("/account/insert")
Result insert(@RequestBody AccountDTO accountDTO);

不能省略@RequestBody直接使用对象参数。

(2)消费者模块启动类上使用@EnableFeignClients注解后一定要指明Feign接口所在的包路径

如:@EnableFeignClients(basePackages = {"com.harvey.feign.client"})

(3)在Feign接口层使用@RequestParam注解要注意,一定要加上value属性

@PostMapping("/account/delete")
Result delete(@RequestParam("id") Long id);

(4)在Feign接口层使用@PathVariable注解要注意,一定要跟上面一样加上value属性

@GetMapping("/account/{id}")
Result getById(@PathVariable(value = "id") Long id);

(5)在消费者配置文件中添加Feign超时时间配置

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]