1 数据库表

  • 用户表:
  1. CREATE TABLE `tb_user` (
  2. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  3. `username` varchar(40) DEFAULT NULL COMMENT '用户名',
  4. `password` varchar(40) DEFAULT NULL COMMENT '密码',
  5. `age` int(3) DEFAULT NULL COMMENT '年龄',
  6. `balance` decimal(10,2) DEFAULT NULL COMMENT '余额',
  7. `address` varchar(80) DEFAULT NULL COMMENT '地址',
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 商品表:
  1. CREATE TABLE `tb_product` (
  2. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  3. `product_name` varchar(40) DEFAULT NULL COMMENT '名称',
  4. `status` int(2) DEFAULT NULL COMMENT '状态',
  5. `price` decimal(10,2) DEFAULT NULL COMMENT '单价',
  6. `product_desc` varchar(255) DEFAULT NULL COMMENT '描述',
  7. `caption` varchar(255) DEFAULT NULL COMMENT '标题',
  8. `inventory` int(11) DEFAULT NULL COMMENT '库存',
  9. PRIMARY KEY (`id`)
  10. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  11. INSERT INTO `tb_product` VALUES (1, 'iPhone', 1, 5000.10, '苹果手机就是香', '苹果哇', 50);
  • 订单表:
  1. CREATE TABLE `tb_order` (
  2. `id` bigint(11) NOT NULL AUTO_INCREMENT,
  3. `user_id` int(11) DEFAULT NULL COMMENT '用户id',
  4. `product_id` int(11) DEFAULT NULL COMMENT '商品id',
  5. `number` int(11) DEFAULT NULL COMMENT '数量',
  6. `price` decimal(10,2) DEFAULT NULL COMMENT '单价',
  7. `amount` decimal(10,2) DEFAULT NULL COMMENT '总额',
  8. `product_name` varchar(40) DEFAULT NULL COMMENT '商品名',
  9. `username` varchar(40) DEFAULT NULL COMMENT '用户名',
  10. PRIMARY KEY (`id`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2 搭建环境

2.1 创建父工程spring_cloud_demo

  • 在IDEA中创建父工程spring_cloud_demo,并引入坐标:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <packaging>pom</packaging>
  7. <modules>
  8. <module>product_service</module>
  9. <module>spring_cloud_common</module>
  10. <module>order_service</module>
  11. </modules>
  12. <parent>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-parent</artifactId>
  15. <version>2.1.6.RELEASE</version>
  16. </parent>
  17. <groupId>org.sunxiaping</groupId>
  18. <artifactId>spring_cloud_demo</artifactId>
  19. <version>1.0</version>
  20. <properties>
  21. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  22. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  23. <java.version>1.8</java.version>
  24. </properties>
  25. <dependencies>
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-test</artifactId>
  33. <scope>test</scope>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.projectlombok</groupId>
  37. <artifactId>lombok</artifactId>
  38. <version>1.18.4</version>
  39. <scope>provided</scope>
  40. </dependency>
  41. </dependencies>
  42. <dependencyManagement>
  43. <dependencies>
  44. <dependency>
  45. <groupId>org.springframework.cloud</groupId>
  46. <artifactId>spring-cloud-dependencies</artifactId>
  47. <version>Hoxton.SR1</version>
  48. <type>pom</type>
  49. <scope>import</scope>
  50. </dependency>
  51. </dependencies>
  52. </dependencyManagement>
  53. <repositories>
  54. <repository>
  55. <id>spring-snapshots</id>
  56. <name>Spring Snapshots</name>
  57. <url>http://repo.spring.io/libs-snapshot-local</url>
  58. <snapshots>
  59. <enabled>true</enabled>
  60. </snapshots>
  61. </repository>
  62. <repository>
  63. <id>spring-milestones</id>
  64. <name>Spring Milestones</name>
  65. <url>http://repo.spring.io/libs-milestone-local</url>
  66. <snapshots>
  67. <enabled>false</enabled>
  68. </snapshots>
  69. </repository>
  70. <repository>
  71. <id>spring-releases</id>
  72. <name>Spring Releases</name>
  73. <url>http://repo.spring.io/libs-release-local</url>
  74. <snapshots>
  75. <enabled>false</enabled>
  76. </snapshots>
  77. </repository>
  78. </repositories>
  79. <pluginRepositories>
  80. <pluginRepository>
  81. <id>spring-snapshots</id>
  82. <name>Spring Snapshots</name>
  83. <url>http://repo.spring.io/libs-snapshot-local</url>
  84. <snapshots>
  85. <enabled>true</enabled>
  86. </snapshots>
  87. </pluginRepository>
  88. <pluginRepository>
  89. <id>spring-milestones</id>
  90. <name>Spring Milestones</name>
  91. <url>http://repo.spring.io/libs-milestone-local</url>
  92. <snapshots>
  93. <enabled>false</enabled>
  94. </snapshots>
  95. </pluginRepository>
  96. </pluginRepositories>
  97. </project>

2.2 创建微服务工程模块

  • 创建商品微服务模块spring_cloud_product。
  • 创建订单微服务模块spring_cloud_order。

3 搭建商品微服务

3.1 在pom.xml中导入相关jar包的坐标

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring_cloud_demo</artifactId>
  7. <groupId>org.sunxiaping</groupId>
  8. <version>1.0</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>product_service</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-data-jpa</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>mysql</groupId>
  19. <artifactId>mysql-connector-java</artifactId>
  20. </dependency>
  21. </dependencies>
  22. <build>
  23. <plugins>
  24. <plugin>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-maven-plugin</artifactId>
  27. <version>2.2.2.RELEASE</version>
  28. <configuration>
  29. <fork>true</fork>
  30. </configuration>
  31. <executions>
  32. <execution>
  33. <goals>
  34. <goal>repackage</goal>
  35. </goals>
  36. </execution>
  37. </executions>
  38. </plugin>
  39. </plugins>
  40. </build>
  41. </project>

3.2 编写实体类

  • Product.java
  1. package com.sunxiaping.product.domain;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. import lombok.NoArgsConstructor;
  5. import lombok.Setter;
  6. import javax.persistence.*;
  7. import java.io.Serializable;
  8. import java.math.BigDecimal;
  9. @Setter
  10. @Getter
  11. @AllArgsConstructor
  12. @NoArgsConstructor
  13. @Entity
  14. @Table(name = "tb_product")
  15. public class Product implements Serializable {
  16. @Id
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. private Long id;
  19. @Column(name = "product_name")
  20. private String productName;
  21. @Column(name = "status")
  22. private Integer status;
  23. @Column(name = "price")
  24. private BigDecimal price;
  25. @Column(name = "product_desc")
  26. private String productDesc;
  27. @Column(name = "caption")
  28. private String caption;
  29. @Column(name = "inventory")
  30. private String inventory;
  31. }

3.3 编写dao层

  • ProductDao.java
  1. package com.sunxiaping.product.dao;
  2. import com.sunxiaping.product.domain.Product;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
  5. import org.springframework.stereotype.Repository;
  6. @Repository
  7. public interface ProductRepository extends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {
  8. }

3.4 编写service层

  • ProductService.java
  1. package com.sunxiaping.product.service;
  2. import com.sunxiaping.product.domain.Product;
  3. public interface ProductService {
  4. /**
  5. * 根据id查询
  6. *
  7. * @param id
  8. * @return
  9. */
  10. Product findById(Long id);
  11. /**
  12. * 保存
  13. *
  14. * @param product
  15. */
  16. void save(Product product);
  17. /**
  18. * 更新
  19. *
  20. * @param product
  21. */
  22. void update(Product product);
  23. /**
  24. * 删除
  25. *
  26. * @param id
  27. */
  28. void delete(Long id);
  29. }
  • ProductServiceImpl.java
  1. package com.sunxiaping.product.service.impl;
  2. import com.sunxiaping.product.dao.ProductRepository;
  3. import com.sunxiaping.product.domain.Product;
  4. import com.sunxiaping.product.service.ProductService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import javax.transaction.Transactional;
  8. @Service
  9. @Transactional
  10. public class ProductServiceImpl implements ProductService {
  11. @Autowired
  12. private ProductRepository productRepository;
  13. @Override
  14. public Product findById(Long id) {
  15. return productRepository.findById(id).orElse(new Product());
  16. }
  17. @Override
  18. public void save(Product product) {
  19. productRepository.save(product);
  20. }
  21. @Override
  22. public void update(Product product) {
  23. productRepository.save(product);
  24. }
  25. @Override
  26. public void delete(Long id) {
  27. productRepository.deleteById(id);
  28. }
  29. }

3.5 编写controller层

  • ProductController.java
  1. package com.sunxiaping.product.controller;
  2. import com.sunxiaping.product.domain.Product;
  3. import com.sunxiaping.product.service.ProductService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.*;
  6. @RestController
  7. @RequestMapping(value = "/product")
  8. public class ProductController {
  9. @Autowired
  10. private ProductService productService;
  11. @PostMapping(value = "/save")
  12. public String save(@RequestBody Product product) {
  13. productService.save(product);
  14. return "新增成功";
  15. }
  16. @GetMapping(value = "/findById/{id}")
  17. public Product findById(@PathVariable(value = "id") Long id) {
  18. return productService.findById(id);
  19. }
  20. }

3.6 配置yml文件

  • application.yml
  1. server:
  2. port: 9001 # 微服务的端口号
  3. spring:
  4. application:
  5. name: service-product # 微服务的名称
  6. datasource:
  7. url: jdbc:mysql://192.168.237.100:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. username: root
  10. password: 123456
  11. jpa:
  12. generate-ddl: true
  13. show-sql: true
  14. open-in-view: true
  15. database: mysql

3.7 配置启动类

  • ProductApplication.java
  1. package com.sunxiaping.product;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.autoconfigure.domain.EntityScan;
  5. @SpringBootApplication
  6. public class ProductApplication {
  7. public static void main(String[] args) {
  8. SpringApplication.run(ProductApplication.class, args);
  9. }
  10. }

4 搭建订单微服务

4.1 在pom.xml中导入相关jar包的坐标

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring_cloud_demo</artifactId>
  7. <groupId>org.sunxiaping</groupId>
  8. <version>1.0</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>order_service</artifactId>
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-data-jpa</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>mysql</groupId>
  19. <artifactId>mysql-connector-java</artifactId>
  20. </dependency>
  21. </dependencies>
  22. </project>

4.2 编写实体类

  • Product.java
  1. package com.sunxiaping.order.domain;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. import lombok.NoArgsConstructor;
  5. import lombok.Setter;
  6. import javax.persistence.*;
  7. import java.io.Serializable;
  8. import java.math.BigDecimal;
  9. @Setter
  10. @Getter
  11. @AllArgsConstructor
  12. @NoArgsConstructor
  13. @Entity
  14. @Table(name = "tb_product")
  15. public class Product implements Serializable {
  16. @Id
  17. @GeneratedValue(strategy = GenerationType.IDENTITY)
  18. private Long id;
  19. @Column(name = "product_name")
  20. private String productName;
  21. @Column(name = "status")
  22. private Integer status;
  23. @Column(name = "price")
  24. private BigDecimal price;
  25. @Column(name = "product_desc")
  26. private String productDesc;
  27. @Column(name = "caption")
  28. private String caption;
  29. @Column(name = "inventory")
  30. private String inventory;
  31. }

4.3 配置yml

  • application.yml
  1. server:
  2. port: 9002 # 微服务的端口号
  3. spring:
  4. application:
  5. name: service-order # 微服务的名称
  6. datasource:
  7. url: jdbc:mysql://192.168.237.100:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. username: root
  10. password: 123456
  11. jpa:
  12. generate-ddl: true
  13. show-sql: true
  14. open-in-view: true
  15. database: mysql

4.4 配置启动类

  • OrderApplication.java
  1. package com.sunxiaping.order;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class OrderApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(OrderApplication.class, args);
  8. }
  9. }

4.5 服务调用

4.5.1 概述

  • 在用户下单的时候需要调用商品微服务获取商品数据,那么应该需要怎么做呢?商品微服务提供了供人调用的HTTP接口,所以下订单的时候使用HTTP请求的相关工具类完成,如常见的HttpClient、OkHttp,当然也可以使用Spring提供的RestTemplate。

4.5.2 RestTemplate介绍

  • Spring框架提供的RestTemplate类可用于在应用中调用RESTful服务,它简化了和HTTP服务的通信方式,统一了RESTful的标准,封装了HTTP的链接,我们只需要传入URL和返回值类型即可。相较于之前常用的HttpClient、OkHttp等,RestTemplate是一种更加优雅的调用RESTful服务的方式。
  • 在Spring应用程序中访问第三方REST服务和Spring的RestTemplate类有关。RestTemplate类的设计原则和许多其他Spring模块类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。
  • RestTemplate默认依赖JDK提供HTTP连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为如Apache HttpComponents、Netty或OkHttp等其他HTTP库。
  • 考虑到RestTemplate类是为调用REST服务而设计的,因此他的主要方法和REST的基础紧密相连就不足为奇,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。例如,RestTemplate类具有headForHeaders()、getForObject()等方法。

4.6 向Spring容器中注册RestTemplate

  • SpringConfig.java
  1. package com.sunxiaping.order.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.client.RestTemplate;
  5. @Configuration
  6. public class SpringConfig {
  7. @Bean
  8. public RestTemplate restTemplate(){
  9. return new RestTemplate();
  10. }
  11. }

4.7 编写下单方法

  • OrderController.java
  1. package com.sunxiaping.order.controller;
  2. import com.sunxiaping.product.domain.Product;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.PathVariable;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import org.springframework.web.client.RestTemplate;
  9. @RestController
  10. @RequestMapping(value = "/order")
  11. public class OrderController {
  12. @Autowired
  13. private RestTemplate restTemplate;
  14. /**
  15. * 通过订单系统,调用商品微服务根据id查询商品信息
  16. *
  17. * @param id
  18. * @return
  19. */
  20. @GetMapping(value = "/buy/{id}")
  21. public Product buy(@PathVariable(value = "id") Long id) {
  22. Product product = restTemplate.getForObject("http://localhost:9001/product/findById/" + id, Product.class);
  23. return product;
  24. }
  25. }

5 分析模拟微服务中存在的问题

  • 模拟微服务环境 - 图1服务调用者将微服务的请求路径硬编码到Java代码中。
  • 模拟微服务环境 - 图2不能对微服务负载均衡的调用,因为请求路径的URL硬编码了。
  • 模拟微服务环境 - 图3服务多起来,对前端调用不友好,需要加入API网关。
  • 模拟微服务环境 - 图4微服务多起来的话,如果每次都需要重新修改配置文件,很麻烦,需要配置的统一管理。
  • 模拟微服务环境 - 图5链路追踪。
  • 模拟微服务环境 - 图6系统容错。
  • 模拟微服务环境 - 图7……

分析模拟微服务中存在的问题.jpg