两个微服务之间的调用
微服务我自己的理解是对不同实体的具体操作的集合。比如两个实体订单和商品,一个订单里面可以包含多个商品,我们在对订单进行操作,比如需要打印订单,即需要知道订单的具体内容,而订单的具体内容包含订单的编号,订单的时间等等,还包括商品,即包含一个商品的对象,而商品的操作是在另外一个项目中的,并不是和订单操作在一个项目中,这样两个具体的操作就可以单独的构成一个项目,即一种微服务。
微服务就是致力于将这个项目分解成不同的子项目,构成单独的微服务,各个微服务可以自己单独的运行,并且可以分布在不同的项目,不同的服务器上面。因此,需要构造一种方法使得不同的项目之间可以互相调用方法。下面开始进行实战。
首先针对商品的服务,我们需要构建一个项目,为这个服务单独的构建一个项目,这个项目可以自己单独的运行,这种项目和之前的spring boot项目是一样的。方法:构建一个maven项目,在POM文件中导入依赖,添加入口类,这样就可以简单的运行了。
商品微服务
1、构建商品服务的项目,项目构建完成后需要在配置文件中修改服务的端口号,一个微服务对应一个端口号,端口号可以自己设置,我这里设置的是8081
2、构建入口类
package com.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ItemApplication {
public static void main(String []args) {
SpringApplication.run(ItemApplication.class, args);
}
}
3、构建商品实体类Item
package com.application.entity;
public class Item {
private Long id;
private String title;
//图片
private String pic;
private String desc;
private Long price;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Item [id=" + id + ", title=" + title + ", pic=" + pic + ", desc=" + desc + ", price=" + price + "]";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPic() {
return pic;
}
public Item() {}
public Item(Long id, String title, String pic, String desc, Long price) {
super();
this.id = id;
this.title = title;
this.pic = pic;
this.desc = desc;
this.price = price;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
}
实体类添加了无参的构造函数和有参的构造函数,并且添加了toString方法,这是为了待会儿进行测试的时候模仿打印商品的信息操作。
4、构建商品服务的类
这个类可以针对商品进行不同的操作,比如增加商品,减少商品,即针对商品进行增删改查等操作。这里只是简单的查询操作。
package com.application.service;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.application.entity.Item;
@Component
public class ItemService {
private static final Map<Long, Item> MAP=new HashMap<Long, Item>();
//准备一些静态数据
static {
MAP.put(1L, new Item(1L,"商品标题1","http://图片1","商品描述1",1000L));
MAP.put(2L, new Item(2L,"商品标题2","http://图片2","商品描述2",1000L));
MAP.put(3L, new Item(3L,"商品标题3","http://图片3","商品描述3",1000L));
MAP.put(4L, new Item(4L,"商品标题4","http://图片4","商品描述4",1000L));
MAP.put(5L, new Item(5L,"商品标题5","http://图片5","商品描述5",1000L));
MAP.put(6L, new Item(6L,"商品标题6","http://图片6","商品描述6",1000L));
}
/**
* 模拟商品查询
*/
public Item queryItemById(Long id)
{
return MAP.get(id);
}
}
5、添加控制类
package com.application.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.application.entity.Item;
import com.application.service.ItemService;
@RestController
public class ItemController {
//直接配置将itemservice注入spring bean
@Autowired
private ItemService itemService;
/**
* 对外提供接口服务,查询商品的信息
*
*
*/
@RequestMapping(value="/item/{id}" )
public Item queryItemById(@PathVariable("id")Long id)
{
return this.itemService.queryItemById(id);
}
}
这个控制类即与表现层进行交互,可以通过请求来进行操作,因此控制类专门负责项目的控制,model层的就不归它管了。这里也是为其他项目服务提供了接口,其他项目可以通过这个URL来访问这个方法来进行交互。
比如另一个服务需要根据商品id来查询商品信息的方法,具体实现为:项目根据路由找到这个控制类的这个方法,然后这个方法返回一个Item对象,然后那个调用者就可以接收到返回的数据并反序列化得到这个方法传递过去的Item对象,这样就完成了一个不同微服务之间的交互。
以上的操作完成后就可以运行这个项目了,可以根据id查询商品的信息。
运行结果:
订单微服务
1、构建订单项目,在配置文件中修改端口号,我这里设置的是8082
2、构建入口类
package com.application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class orderApplication {
//向spring容器中添加RestTemplate对象
@Bean
public RestTemplate restTemplate()
{
return new RestTemplate();
}
public static void main(String []args)
{
SpringApplication.run(orderApplication.class, args);
}
}
这里添加了一个RestTemplate类的对象,这个对象的作用就是通过路由来找到需要访问商品服务中根据id查找商品信息。
3、构建实体类
Order类
package com.application.entity;
import java.util.Date;
import java.util.List;
public class Order {
private String orderId;
private Long userId;
private Date createDate;
private Date updateDate;
//一个订单的详细信息包含一个商品订单的id和一个对应的商品,一个订单包含多个商品,因此对应多个商品的详细信息。
private List<OrderDetail> orderDetails;
public Order()
{
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public List<OrderDetail> getOrderDetails() {
return orderDetails;
}
public void setOrderDetails(List<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", userId=" + userId + ", createDate=" + createDate + ", updateDate="
+ updateDate + "]";
}
}
orderDetail类:
package com.application.entity;
public class OrderDetail {
private String orderId;
private Item item=new Item();
public OrderDetail()
{
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Item getItem() {
return item;
}
public OrderDetail(String orderId, Item item) {
super();
this.orderId = orderId;
this.item = item;
}
public void setItem(Item item) {
item = item;
}
@Override
public String toString() {
return "OrderDetail [orderId=" + orderId +",item="+ item+"]";
}
}
这个类就相当于在order和Item中构建了一个桥梁
这里还是需要一个商品的实体类,和前面的类一样。
Item:
package com.application.entity;
public class Item {
private Long id;
private String title;
//图片
private String pic;
private String desc;
private Long price;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Item [id=" + id + ", title=" + title + ", pic=" + pic + ", desc=" + desc + ", price=" + price + "]";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPic() {
return pic;
}
public Item() {}
public Item(Long id, String title, String pic, String desc, Long price) {
super();
this.id = id;
this.title = title;
this.pic = pic;
this.desc = desc;
this.price = price;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
}
4、构建服务类
OrderService:
package com.application.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.application.entity.Item;
import com.application.entity.Order;
import com.application.entity.OrderDetail;
@Service
public class OrderService {
private static final Map<String , Order> MAP=new HashMap<String, Order>();
//构造测试数据
static {
Order order=new Order();
order.setOrderId("5656545878");
order.setCreateDate(new Date());
order.setUpdateDate(order.getCreateDate());
order.setUserId(1L);
List<OrderDetail> orderDetails=new ArrayList<OrderDetail>();
Item item=new Item();
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);
MAP.put(order.getOrderId(), order);
}
//这里表示的是商品的服务,即针对商品进行增删查改操作的服务
@Autowired
private ItemService itemService;
public Order queryOrderById(String orderId)
{
Order order=MAP.get(orderId);
if(order==null)
{
return null;
}
List< OrderDetail> orderDetails=order.getOrderDetails();
for(OrderDetail orderDetail : orderDetails)
{
Item item=this.itemService.queryItemById(orderDetail.getItem().getId());
if(item==null)
{
continue;
}
orderDetail.setItem(item);
}
return order;
}
}
ItemService
package com.application.service;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.application.entity.Item;
@Service
public class ItemService {
/*
* spring框架对restful方式的http请求做了封装,简化操作
* 通过以下的对象来取得http请求,访问地址拿到对象
*/
@Autowired
private RestTemplate restTemplate;
/*
* 这里通过调用ItemMicroservice项目中的操作来实现,
* 调用接口地址
*/
//下面就是通过restTemplate对象来获取指定路由的方法来实现交互
public Item queryItemById(Long id)
{
String url="http://localhost:8081/item/"+id;
//第二个参数为反序列化的对象
return this.restTemplate.getForObject(url, Item.class);
}
}
5、 控制类
package com.application.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.application.entity.Order;
import com.application.service.OrderService;
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("order/{orderId}")
public Order queryOrderById(@PathVariable("orderId") String orderId)
{
return this.orderService.queryOrderById(orderId);
}
}
这样就项目就可以运行并且完成与Item项目的交互。
运行截图:
总结:分布式框架就是可以将这个项目分为不同的子项目组成不同的微服务,并且这些微服务是可以分布在不同的服务器上面的。如果一个服务需要访问另一个服务的某个方法,只需要知道这个服务这个方法的URL路由,就可以用RestTemplate对象通过这个路由来进行访问并返回结果。当然,前提是被访问的这个微服务是正在运行的,如果被访问的微服务的服务器关闭了,那当然就无法访问。
另外,提醒一下,这是一个spring boot项目,因此项目包的结构必须要满足spring boot的结构来,不然就无法运行,即所有的类都应该是在入口类所在包的下面。