Declarative REST Client: Feign (声明式REST服务调用)
通过spring官方文档可以了解到,Feign是一个声明式web 服务调用服务,他使得一切web服务得以简化。我们只需要创建一个接口并用注解和JAX-RS注解的方式来配置它,即可完成对服务提供方的接口绑定。
具体操作
在原来的订单服务上修改原始消费方式
先来回顾一下原始的商品服务调用方式
1、将RestTemplate注入
/**
* 向Spring容器中定义RestTemplate对象
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
2、在ItemService 服务类中,通过restTemplate调用服务
@Service
public class ItemService {
// Spring框架对RESTful方式的http请求做了封装,来简化操作
@Autowired
private RestTemplate restTemplate;
public Item queryItemById(Long id) {
// 该方法走eureka注册中心调用(去注册中心根据app-item查找服务,这种方式必须先开启负载均衡@LoadBalanced)
String itemUrl = "http://app-goods/item/{id}";
return restTemplate.getForObject(itemUrl, Item.class, id);
/*对比可以发现,使用eureka还是很方便的,只是把地址换成为服务名称
return this.restTemplate.getForObject("http://127.0.0.1:8080/item/{id}"
, Item.class,id);*/
}
}
修改为通过Feign服务调用
在pom中引入feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在应启动类APP增加Feign注解,如下:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class,args);
}
/**
* 向Spring容器中定义RestTemplate对象
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
创建IItemServiceInterface商品服务接口
package com.joery.order.service;
import com.joery.order.entity.Item;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient( value = "app-goods" )
public interface IItemServiceInterface {
@GetMapping(value = "item/{id}")
Item getItem(@PathVariable("id") Long id);
}
主要是通过FeignClient注解,实现服务调用。
具体调用类注入接口并调用即可:
package com.joery.order.service;
import com.joery.order.entity.Item;
import com.joery.order.entity.Order;
import com.joery.order.entity.OrderDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
@Service
public class OrderService {
private static final Map<String, Order> ORDER_DATA = new HashMap<String, Order>();
@Autowired
private ItemService itemService;
@Resource
IItemServiceInterface iItemServiceInterface;
static {
// 模拟数据库,构造测试数据
Order order = new Order();
order.setOrderId("201810300001");
order.setCreateDate(new Date());
order.setUpdateDate(order.getCreateDate());
order.setUserId(1L);
List<OrderDetail> orderDetails = new ArrayList<OrderDetail>();
Item item = new Item();// 此处并没有商品的数据,只是保存了商品ID,需要调用商品微服务获取
item.setId(1L);
orderDetails.add(new OrderDetail(order.getOrderId(), item));
item = new Item(); // 构造第二个商品数据
item.setId(2L);
orderDetails.add(new OrderDetail(order.getOrderId(), item));
order.setOrderDetails(orderDetails);
ORDER_DATA.put(order.getOrderId(), order);
}
/**
* 根据订单id查询订单数据
*
* @param orderId
* @return
*/
public Order queryOrderById(String orderId) {
Order order = ORDER_DATA.get(orderId);
if (null == order) {
return null;
}
List<OrderDetail> orderDetails = order.getOrderDetails();
for (OrderDetail orderDetail : orderDetails) {
// 通过商品微服务查询商品详细数据
// Item item = this.itemService.queryItemById(orderDetail.getItem()
// .getId());
Item item = iItemServiceInterface.getItem(orderDetail.getItem().getId());
if (null == item) {
continue;
}
orderDetail.setItem(item);
}
return order;
}
}
@Resource
IItemServiceInterface iItemServiceInterface;
注入接口,并通过Item item = iItemServiceInterface.getItem(orderDetail.getItem().getId());直接调用服务。
注意在项目中实体类和接口可以单独出来项目,以便使用者直接引入该maven包即可。