「整合系列」服务调用(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
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]