1、前言
微服务项目中,我们会把项目细化,按照功能模块拆分成不相同的微服务,每一个微服务都是一个独立的 moudle。该 moudle 的既是服务也是应用,也就是我们原始的单体项目架构。 每一个 moudle 不复杂的时候,这样的拆分就可以了。
但是,当 moudle 里面的配置较多的时候,其实还可以针对 moudle 继续细分。下面就按照继续细分的思路展开说明。
2、拆分思路
按照应用层、服务层、持久层以及公用层拆分成四大模块。如下的树形结构:
simonking-multi
├── simonking-api 【api服务层】
├── simonking-common 【公用层】
│ ├── simonking-common-kafka
│ └── simonking-common-redis
├── simonking-resposity 【持久层】
└── simonking-server 【控制层】
3、模块说明
simonking-server 控制层
控制层:该控制层包含了springmvc三层架构的Controller和Service。主要用来数据参数校验、数据渲染以及业务逻辑。
其中Controller用来处理参数的校验,数据的渲染,Service用来处理业务逻辑。遵循springmvc的三层架构。
simonking-resposity 持久层
持久层:主要用来处理数据库连接的相关代码。比如分页插件的配置、分布式id、分布式事务等。
持久层的框架有很多,其中mybatisplus帮我们封装了很多单表操作的方法,不需要再写sql。其中xxxWrapper类可以通过代码的形式拼接sql。
正因为xxxWrapper类的提供,我们在开发中为了方便使用,可能就直接自己在控制层直接使用,导致业务代码合数据库相关的代码冗余在一起。这也是很多高级程序员不建议使用的原因。会导致后期不好维护,难以管理,为后期sql优化的维护带来不便。
笔者也是用mybatisplus,把sql的拼接全部下沉到持久层。如下:
public interface UserInfoWrapperMapper extends BaseMapper<UserInfo> {
default UserInfo getUserByName(String userName){
QueryWrapper<UserInfo> userQuery = new QueryWrapper<>();
userQuery.eq("name", userName);
userQuery.last("limit 1");
return this.selectOne(userQuery);
}
}
public interface UserInfoMapper extends UserInfoWrapperMapper {
UserInfo getUserByJobSql(@Param("job") String job);
}
然后再定义xxxxMapper继承xxxWrapperMaper就可以了。所有的xxxWrapper相关的sql拼接全部写在UserInfoWrapperMapper接口里面。其中必须依赖java8,只有java8及以上才可以使用default在接口里面默认实现。
simonking-common 公用层
公用层:主要用来管理一些中间件,未来可以独立出去,给所有的微服务使用。这样的好处就是中间件可以统一管理。 这样一来中间件相关的配置、常量都可以统一管理。
simonking-api 服务层
服务层:主要用来定义一些对外暴露的接口,给其他业务提供微服务。
4、在搭建过程中出现的问题总结
- 4.1 所有的yml配置文件应该统一在simonking-server控制层配置。
- 4.2 依赖关关系保持单一依赖,皮面循环依赖。控制能依赖其他的三个模块。
- 4.3 为了保证控制层启动的能够扫描到mybatisplus的配置,使用spring.factoroiesde特性。
@Configuration
@MapperScan("com.simonking.resposity.mapper")
@ComponentScan(basePackages = {"com.simonking.resposity"})
public class MybatisPlusConfig {
}
- 4.4 mapstruct和lombok一起使用,有两种方式。
第一种直接引入依赖坐标:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<scope>provided</scope>
</dependency>
第二种mapstruct的官方推荐写法:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<scope>provided</scope>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
第二种写法的plugin必须写在控制层的pom里面,如果写在parent的pom中lombok就会失效。