写在前面:
这是一个分布式demo,方便今后搭建分布式项目的时候直接使用。
项目从传统项目着手,逐步改造成高可用的分布式,eureka、ribbon、hystrix、zuul、config 等,浅显的涉及到微服务的拆分,负载均衡,服务降级,路由网关等。
源码地址GitHub:https://github.com/Mujio-killer/mall.git
一直想学习一下Spring Cloud,奈何苦于Spring Cloud全家人口众多,不知道该如何入手;再者相关的demo在网上比较难找,特别是从零搭建而且能正常运行的少之又少。本文是参考多篇博文,在实际搭建验证过后写的,主要配置均能够实现对应功能,在此基础上也会去探究其他相关配置,有验证疏漏之处欢迎指出。
主要参考:简书Felix独箸
开发环境:win10 jdk1.8 IDEA 2019.1
一个传统项目,本文使用spring boot下的商城demo,若已有项目可直接跳到第二节。
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<groupId>com.mujiogroupId>
<artifactId>mallartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>mallname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.41version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
package com.mujio.mall;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.mujio.*.mapper")
public class MallApplication {
public static void main(String[] args) {
SpringApplication.run(MallApplication.class, args);
}
}
package com.mujio.mall.controller;
import com.mujio.mall.entity.Order;
import com.mujio.mall.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/order")
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("/{id}")
@ResponseBody
public Order getOrder(@PathVariable("id") int id){
return orderService.getOrder(id);
}
}
package com.mujio.mall.controller;
import com.mujio.mall.entity.Goods;
import com.mujio.mall.service.GoodService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/goods")
@RestController
public class GoodsController {
@Autowired
private GoodService goodService;
@RequestMapping("/{id}")
@ResponseBody
public Goods getGoods(@PathVariable("id") int id){
return goodService.getGoods(id);
}
}
package com.mujio.mall.service;
import com.mujio.mall.entity.Goods;
import com.mujio.mall.entity.Order;
import com.mujio.mall.mapper.ConnMapper;
import com.mujio.mall.mapper.GoodsMapper;
import com.mujio.mall.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class OrderService {
@Autowired
private ConnMapper connMapper;
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private OrderMapper orderMapper;
public Order getOrder(int id){
Order order = new Order();
order.setId(id);
List<Integer> list = connMapper.getConn(id);
List<Goods> goodsList = new ArrayList<>();
for (int goodsid: list ) {
goodsList.add(goodsMapper.getGoods(goodsid));
}
order.setGoodsList(goodsList);
order.setCreatedate(orderMapper.getOrder(id).getCreatedate());
return order;
}
}
package com.mujio.mall.service;
import com.mujio.mall.entity.Goods;
import com.mujio.mall.mapper.GoodsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class GoodService {
@Autowired
private GoodsMapper goodsMapper;
public Goods getGoods(int id){
return goodsMapper.getGoods(id);
}
}
package com.mujio.mall.mapper;
import com.mujio.mall.entity.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface OrderMapper {
@Select("select * from orders where id = #{id}")
Order getOrder(int id);
}
package com.mujio.mall.mapper;
import com.mujio.mall.entity.Goods;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface GoodsMapper {
@Select("select * from goods where id = #{id}")
Goods getGoods(int id);
}
package com.mujio.mall.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface ConnMapper {
@Select("select goodsid from conn where orderid = #{id}")
List<Integer> getConn(int id);
}
package com.mujio.mall.entity;
import java.util.Date;
import java.util.List;
public class Order {
private int id;
private List<Goods> goodsList;
private Date createdate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<Goods> getGoodsList() {
return goodsList;
}
public void setGoodsList(List<Goods> goodsList) {
this.goodsList = goodsList;
}
public Date getCreatedate() {
return createdate;
}
public void setCreatedate(Date createdate) {
this.createdate = createdate;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", goodsList=" + goodsList +
", createdate=" + createdate +
'}';
}
}
package com.mujio.mall.entity;
public class Goods {
private int id;
private String name;
private String price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", name='" + name + '\'' +
", price='" + price + '\'' +
'}';
}
}
package com.mujio.mall.entity;
import java.util.List;
public class Conn {
private int id;
private int orderid;
private List goodlist;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public List getGoodlist() {
return goodlist;
}
public void setGoodlist(List goodlist) {
this.goodlist = goodlist;
}
}
#服务开放端口配置
server.port=8080
#数据库连接配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mall?characterEncoding=utf8&useUnicode=true&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=123
/*
Navicat MySQL Data Transfer
Source Server : mujio
Source Server Version : 50045
Source Host : localhost:3306
Source Database : mall
Target Server Type : MYSQL
Target Server Version : 50045
File Encoding : 65001
Date: 2020-03-23 14:35:14
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for conn
-- ----------------------------
DROP TABLE IF EXISTS `conn`;
CREATE TABLE `conn` (
`id` int(11) NOT NULL auto_increment,
`orderid` int(11) default NULL,
`goodsid` int(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of conn
-- ----------------------------
INSERT INTO `conn` VALUES ('1', '1', '1');
INSERT INTO `conn` VALUES ('2', '1', '2');
INSERT INTO `conn` VALUES ('3', '1', '3');
INSERT INTO `conn` VALUES ('4', '2', '4');
INSERT INTO `conn` VALUES ('5', '2', '5');
INSERT INTO `conn` VALUES ('6', '3', '6');
INSERT INTO `conn` VALUES ('7', '3', '7');
INSERT INTO `conn` VALUES ('8', '4', '8');
INSERT INTO `conn` VALUES ('9', '5', '9');
INSERT INTO `conn` VALUES ('10', '6', '10');
INSERT INTO `conn` VALUES ('11', '6', '1');
INSERT INTO `conn` VALUES ('12', '6', '2');
INSERT INTO `conn` VALUES ('13', '7', '3');
INSERT INTO `conn` VALUES ('14', '7', '4');
INSERT INTO `conn` VALUES ('15', '8', '5');
INSERT INTO `conn` VALUES ('16', '8', '6');
INSERT INTO `conn` VALUES ('17', '8', '7');
INSERT INTO `conn` VALUES ('18', '9', '8');
INSERT INTO `conn` VALUES ('19', '9', '9');
INSERT INTO `conn` VALUES ('20', '10', '10');
INSERT INTO `conn` VALUES ('21', '10', '4');
-- ----------------------------
-- Table structure for goods
-- ----------------------------
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`price` double default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES ('1', '电脑', '7299');
INSERT INTO `goods` VALUES ('2', '鼠标', '49');
INSERT INTO `goods` VALUES ('3', '键盘', '239');
INSERT INTO `goods` VALUES ('4', '鼠标垫', '9');
INSERT INTO `goods` VALUES ('5', '转接口', '39');
INSERT INTO `goods` VALUES ('6', '电脑包', '109');
INSERT INTO `goods` VALUES ('7', '手写板', '319');
INSERT INTO `goods` VALUES ('8', '显示器', '699');
INSERT INTO `goods` VALUES ('9', '固态', '659');
INSERT INTO `goods` VALUES ('10', '内存', '229');
-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL auto_increment,
`createdate` datetime default NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('1', '2020-03-23 11:10:03');
INSERT INTO `orders` VALUES ('2', '2020-03-23 11:10:08');
INSERT INTO `orders` VALUES ('3', '2020-03-23 11:10:10');
INSERT INTO `orders` VALUES ('4', '2020-03-23 11:10:13');
INSERT INTO `orders` VALUES ('5', '2020-03-23 11:10:16');
INSERT INTO `orders` VALUES ('6', '2020-03-23 11:10:19');
INSERT INTO `orders` VALUES ('7', '2020-03-23 11:10:21');
INSERT INTO `orders` VALUES ('8', '2020-03-23 11:10:24');
INSERT INTO `orders` VALUES ('9', '2020-03-23 11:10:28');
INSERT INTO `orders` VALUES ('10', '2020-03-23 11:10:30');
访问:http://localhost:8080/order/1
访问:http://localhost:8080/goods/1
到这里只是一个普通的单体web项目,当业务量达到一定程度的时候,这样的结构很难满足需求,这时候就需要进行业务的拆分。下一节开始,将实现订单服务与商品服务的拆分。