Spring Cloud【Finchley】专栏
如果还没有系统的学过Spring Cloud ,先到我的专栏去逛逛吧
Spring Cloud 【Finchley】手札
概述
上篇博文 Spring Cloud实战-03订单微服务与商品微服务之间的调用 我们虽然打通了订单流程,但是还是有些问题需要去修改和完善下
- 问题一:将数据表映射的实体类暴露出去了,建议最好再封装一层

问题二:同一个对象在不同微服务之间重复定义
我们在Order微服中使用Feign调用Product微服务提供的一些接口时 ,原本属于product微服务的Product和CartDTO类为了不报错却不得不在Order为服务中重复定义,维护较为麻烦。 原则是:这些类该属于哪个模块就在哪个模块定义。


问题三: 将对方的服务定义到自己的服务中
order和product 可能是两个小组来开发,而我们要在order微服中将product微服务的请求的url写到自己的为服务中,将对方的服务定义到自己的服务中是不是不太合理? 应该自己管理自己的对外接口,暴露出去供外部调用者使用。

那如何解决上述问题呢? 答案就是利用maven的多模块技术,将服务拆分为多个子模块。
如何拆分SpringBoot项目,阿里小马哥有个视频讲的挺好,移步:https://www.imooc.com/video/16354
或者参考我以前的博文 : Maven父子工程的搭建
Product微服务功能分析及多模块拆分
拆分原则
我们将Product划分为3个子模块
- product Client : 对外暴露的接口(目前有查询商品和扣减库存)
- product Common : 公用的对象
三者的依赖关系,
product Server 依赖 product Common
product Client 依赖 product Common
那动手拆分起来吧
Step1. 调整主(父)工程的工程类型 packaging为pom
将packaging 由 jar 改为 pom
<packaging>jar</packaging>
调整为:
<packaging>pom</packaging>

Step2. 新建子模块
选中artisan-product工程 右键 New — Module ,
一定要选Maven

啥都不用勾选,默认下一步

Next

确认下,默认即可,点击 Finish结束 。
回头查看父工程的pom.xml 已经新增了 modules节点如下信息

再看下新建的子模块 product-server

未完待续…
2019-03-31续
经过了一周丧心病狂的加班,周末终于有时间了,那我们继续吧
先建好3个子Module(方式同上),然后再将代码按照模块的划分分别整合到各个子模块中。

模块已经建好,根据确定好的拆分原则那将代码按照模块的划分分别整合到各个子模块中吧。
几个注意事项:
- 凡是版本的定义,都建议放在最外层的dependencyManagement中,方便做到统一管理
- 依赖的模块,需要先mvn install ,其他模块才可以正确的引用
父pom
<?xml version="1.0" encoding="UTF-8"?>
<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>com.artisan</groupId>
<artifactId>artisan-product</artifactId>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>product-server</module>
<module>product-client</module>
<module>product-common</module>
</modules>
<packaging>pom</packaging>
<name>artisan-product</name>
<description>Product</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<productcommon.version>0.0.1-SNAPSHOT</productcommon.version>
<springcloud.version>Finchley.RELEASE</springcloud.version>
</properties>
<!-- 凡是版本的定义,都建议放在最外层的dependencyManagement中,方便做到统一管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- product-server和product-client都需要依赖该模块,
在这里定义版本之后,在server和client模块引用的话就无需再加上version了,方便统一管理 -->
<dependency>
<groupId>com.artisan</groupId>
<artifactId>product-common</artifactId>
<version>${productcommon.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
product common
主要是解决问题一将数据表映射的实体类暴露出去了,建议最好再封装一层

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>artisan-product</artifactId>
<groupId>com.artisan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-common</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
product client
主要是解决问题二同一个对象在不同微服务之间重复定义以及问题三自己的服务写到自己的工程中。
那么我们就将属于product微服务的ProductClient定义在该模块中

product client 依赖 product common
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>artisan-product</artifactId>
<groupId>com.artisan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.artisan</groupId>
<artifactId>product-common</artifactId>
</dependency>
</dependencies>
</project>
package com.artisan.product.client;
import com.artisan.product.common.DecreaseStockInput;
import com.artisan.product.common.ProductOutput;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@FeignClient(name="ARTISAN-PRODUCT")
public interface ProductClient {
@PostMapping("/product/productListForOrder")
List<ProductOutput> getProductForOrder(List<String> productIdList);
/**
* 这里我们就不用CartDTO了,因为它属于Order工程,我们这里自己在ProductCommon中自己维护一个DTO类
* DecreaseStockInput
* @param decreaseStockInputList
*/
@PostMapping("/product/decreseProduct")
void decreseProduct(List<DecreaseStockInput> decreaseStockInputList);
}
product server
product server也依赖 product common
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>artisan-product</artifactId>
<groupId>com.artisan</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product-server</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.artisan</groupId>
<artifactId>product-common</artifactId>
</dependency>
</dependencies>
<!--打包 放在product-server中-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

ProductController

ProductService 接口

然后删掉些之前的引用即可。
Order微服务的改造
同上,就不多赘述了,详见Github,
目前order-client 和 order-common没有啥需求,先写个空的吧,后续根据需求逐步完善,

其中order-server模块需要说明的是:
因为要调用商品微服务来查询商品和扣减库存,所以要依赖product-client包
<dependency>
<groupId>com.artisan</groupId>
<artifactId>product-client</artifactId>
</dependency>
同时为了让order server微服务启动时实例化Feign接口,需要配置扫描基包 (因为他们不在一个工程的同一级或者子孙级目录中)
@EnableFeignClients(basePackages="com.artisan.product.client")

测试
启动注册中心,通过product-server和order-server中的main函数启动俩微服务,
下单

select * from artisan_order a where a.order_id = '1554135137371873119';
select * from order_detail a where a.order_id = '1554135137371873119';


代码
Github
https://github.com/yangshangwei/springcloud-o2o/tree/master/artisan-product
https://github.com/yangshangwei/springcloud-o2o/tree/master/artisan_order