Spring Boot如何实现微服务?


在正式学习 Spring Cloud 之前我们先使用 Spring Boot 实现一个微服务。

业务非常简单:

(1)商品微服务:通过商品 id 查询商品的服务;

(2)订单微服务:通过订单 id 查询订单数据,同时需要调用商品微服务查询出订单详情数据对应的商品数据

Spring Boot 实现微服务01


说明:

(1)对于商品微服务而言,商品微服务是服务的提供者,订单微服务是服务的消费者;

(2)对于订单微服务而言,订单微服务是服务的提供者,人是服务的消费者。

3.1 实现商品微服务

3.1.1 pom.xml 文件的配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>cn.itcast.microservice</groupId>

<artifactId>itcast-micorservice-item</artifactId>

<version>0.0.1-SNAPSHOT</version>

<!-- 定义变量 -->

<properties>

<java.version>1.8</java.version>

</properties>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>1.5.14.RELEASE</version>

</parent>

<dependencies>

<!-- 加入 web 的支持 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

</dependencies>

</project>

 

3.1.2 创建实体 Item

package cn.itcast.microservice.pojo;

public class Item {

private Long id; // 唯一标识

private String title; // 商品标题

private String pic; // 图片的 pic 地址

private String desc; // 描述信息

private Long price; // 价格

}

 

3.1.3 编写 ItemService

package cn.itcast.microservice.service;

import java.util.HashMap;

import java.util.Map;

import org.springframework.stereotype.Service;

import cn.itcast.microservice.pojo.Item;

@Service

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(1L, "商品标题 2", "http://图片 2", "商品描述 2", 2000L));

MAP.put(3L, new Item(1L, "商品标题 3", "http://图片 3", "商品描述 3", 3000L));

MAP.put(4L, new Item(1L, "商品标题 4", "http://图片 4", "商品描述 4", 4000L));

MAP.put(5L, new Item(1L, "商品标题 5", "http://图片 5", "商品描述 5", 5000L));

MAP.put(6L, new Item(1L, "商品标题 6", "http://图片 6", "商品描述 6", 6000L));

MAP.put(7L, new Item(1L, "商品标题 7", "http://图片 7", "商品描述 7", 7000L));

MAP.put(8L, new Item(1L, "商品标题 8", "http://图片 8", "商品描述 8", 8000L));

}

/**

* 模拟实现商品查询

*

* @param id

* @return

*/

public Item queryItemById(Long id) {

return MAP.get(id);

}

}

 

3.1.4 编写 ItemController

package cn.itcast.microservice.controller;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

import cn.itcast.microservice.pojo.Item;

import cn.itcast.microservice.service.ItemService;

@RestController

public class ItemController {

@Autowired

private ItemService itemService;

/**

* 对外提供接口服务,查询商品信息

*

* @param id

* @return

*/

@GetMapping(value = "/item/{id}")

public Item queryItemById(@PathVariable("id") Long id) {

return this.itemService.queryItemById(id);

}

}

3.1.5 程序入口

package cn.itcast.microservice;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication //声明这是一个 Spring Boot 项目

public class ItemApplication {

public static void main(String[] args) {

SpringApplication.run(ItemApplication.class, args);

}

}


3.1.6 创建配置文件

在 src/main/resources 目录下创建一个 application.properties 配置文件,在该文件中可以配置如下内容:

server.port=8081

指定服务启动占用的端口


3.1.7 启动项目进行访问

Spring-Boot-实现微服务02

 

3.2 实现订单微服务

3.2.1 pom.xml 文件的配置

 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>cn.itcast.microservice</groupId>

<artifactId>itcast-microservice-order</artifactId>

<version>0.0.1-SNAPSHOT</version>

<!-- 定义变量 -->

<properties>

<java.version>1.8</java.version>

</properties>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>1.5.14.RELEASE</version>

</parent>

<dependencies>

<!-- 加入 web 的支持 -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>
</dependencies>

</project>

3.2.2 创建实体 Order

package cn.itcast.microservice.pojo;

import java.util.Date;

import java.util.List;

public class Order {

private String orderId; // 订单的 id

private Long userId; // 用户 id

private Date createDate; // 创建时间

private Date updateDate; // 修改时间

private List<OrderDetail> orderDetails; // 订单详情

}

 

3.2.3 创建实体 OrderDetail

package cn.itcast.microservice.pojo;

public class OrderDetail {

private String orderId ; // 订单 id

private Item item ; // 商品

}

 

3.2.4 复制 Item 实体

Spring-Boot-实现微服务03

3.2.5 编写 OrderService

该 Service 实现的根据订单 Id 查询订单的服务,为了方便测试,我们将构造数据实现,不采用查询数据库的方式。

package cn.itcast.microservice.service;

import java.util.ArrayList;

import java.util.Date;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.springframework.stereotype.Service;

import cn.itcast.microservice.pojo.Item;

import cn.itcast.microservice.pojo.Order;

import cn.itcast.microservice.pojo.OrderDetail;

@Service

public class OrderService {

private static final Map<String, Order> MAP = new HashMap<String, Order>();

static {

// 构造测试数据

Order order = new Order();

order.setOrderId("59193738268961441");

order.setCreateDate(new Date());

order.setUpdateDate(order.getCreateDate());

order.setUserId(1L);

// 创建 OrderDetail 集合对象

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));

// 将 OrderDetail 数据集设置给 Order 对象

order.setOrderDetails(orderDetails);

// 将 Order 对象添加到 Map 中

MAP.put(order.getOrderId(), order);

}

/**

* 根据订单 id 查询订单数据

*

* @param orderId

* @return

*/

public Order queryOrderById(String orderId) {

Order order = MAP.get(orderId);

// 获取 Order 中的 OrderDetail 列表数据,然后遍历集合获取每一个 OrderDetail,然后调用商品微服务根据商品的 id 查询商品数据

return order;

}

}

 

3.2.6 实现 ItemService

package cn.itcast.microservice.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.web.client.RestTemplate;

import cn.itcast.microservice.pojo.Item;

@Service

public class ItemService {

@Autowired

private RestTemplate restTemplate ;

/**

* 根据商品的 id 进行查询

* @param id

* @return

*/

public Item queryById(Long id) {

// 使用 HttpClient 工具发送请求获取商品的数据

// 我们也可以使用 spring 给我们提供的另个一个类 RestTemplate,来发送 Http 请求

Item item = restTemplate.getForObject("http://localhost:8081/item/" + id, Item.class) ;

// 返回

return item ;

}

}

 

3.2.7 完善 OrderService

@Autowired

private ItemService itemService ;

/**

* 根据订单 id 查询订单数据

*

* @param orderId

* @return

*/

public Order queryOrderById(String orderId) {

Order order = MAP.get(orderId);

// 获取 Order 中的 OrderDetail 列表数据,然后遍历集合获取每一个 OrderDetail,然后调用商品微服务根据商品的 id 查询商品数据

for (OrderDetail orderDetail : order.getOrderDetails()) {

Item item = itemService.queryById(orderDetail.getItem().getId()) ;

orderDetail.setItem(item);

}

return order;

}


3.2.8 编写 OrderController

package cn.itcast.microservice.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 cn.itcast.microservice.pojo.Order;

import cn.itcast.microservice.service.OrderService;

@RestController

public class OrderController {

@Autowired

private OrderService orderService;

@GetMapping(value = "/order/{orderId}")

public Order queryOrderById(@PathVariable("orderId") String orderId) {

return this.orderService.queryOrderById(orderId);

}

}

3.2.9 编写启动类

package cn.itcast.microservice;

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 {

@Bean

public RestTemplate restTemplate() {

return new RestTemplate();

}

// 程序入口

public static void main(String[] args) {

/**

* 启动程序

*/

SpringApplication.run(OrderApplication.class, args) ;

}

}

 

3.2.10创建配置文件

在 src/main/resources 目录下创建一个 application.properties 配置文件,在该文件中可以配置如下内容:

server.port=8082

3.2.11启动测试

Spring-Boot-实现微服务04

3.3 发现问题与解决问题

3.3.1 问题描述

在刚才的服务调用过程中我们的商品服务地址是直接写死在程序中,存在硬编码问题

如果商品微服务部署了多个,那么我们订单微服务如何去调用呢?

 

3.3.2 问题处理

1. 关于硬编码的问题我们可以使用配置文件处理,我们可以将地址信息编写到配置文件中,然后读取配置文件获取请求地址信息.

在配置文件中加入如下配置:

itcast.item.url=http://127.0.0.1:8081/item/

修改 ItemService 的实现,通过@Value 注解获取该值

 

package cn.itcast.microservice.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;

import org.springframework.web.client.RestTemplate;

import cn.itcast.microservice.pojo.Item;

@Service

public class ItemService {

@Autowired

private RestTemplate restTemplate ;

@Value("${itcast.item.url}")

private String itemUrl ;

/**

* 根据商品的 id 进行查询

* @param id

* @return

*/

public Item queryById(Long id) {

// 我们也可以使用 spring boot 给我们提供的另个一个类 RestTemplate,来发送 Http 请求

Item item = restTemplate.getForObject(itemUrl + id, Item.class) ;

// 返回

return item ;

}

}

 

注: 我们本次的解决方案只是一种临时的处理方案,如果我们商品微服务的 ip 地址发送了改变,那么我们对应的订单微服务的配置文件也需要做响应的改变,因此这种处理方案并没有本质的解决硬编码的问题。

 

2. 如果商品微服务部署了多个,那么我们订单微服务如何去调用呢?

 

关于这个问题,有的开发人员可能会想。我们可以将多个商品微服务的地址配置到配置文件中,然后在进行读取配置文件的地址,进行调用。听起来好像可以,但是我们需要考虑以后问题就是后期维护的问题。

 

·如果商品微服务的我们又添加或者减少了一个部署,相应的我们需要去更改配置文件的内容。

 

·如果商品微服务的 ip 地址发送了改变,那么我们也需要相应的修改配置文件的地址。

 

所以我们自己这样实现比较麻烦。

 

我们可以使用服务注册于发现机制来完成


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM