- COLA架构使用过程中对各模块的一些理解
- BiliBili视频:https://www.bilibili.com/video/BV1Kw4m1e7oX/
domain
- 与传统结构最大的不同,就是领域层
领域层的作用是让我们使用面相对象的思想去编写领域对象
面相对象
- 初学Java时,一直在强调Java是面相对象语言
对象有属性和方法(行为)
public class Dog { String name; int age; void eat() { } void run() { } }
面相表格
- 工作一段时间后,感觉较面向表格更为贴切
从数据库获取一行数据,修改某些属性,再保存回去
- 包含大量胶水代码,无法复用
@Data public class User { private Long id; private String name; private Integer age; private String password; }
public class UserService { @Autowired private UserMapper userMapper; public void changeInfo(Long id) { User user = userMapper.selectById(id); user.setName("张三"); user.setAge(18); user.setPassword(getMd5("123456")); userMapper.updateById(user); } private String getMd5(String password) { return password + "-md5"; // 模拟 } }
领域对象
- 领域对象其实是回归面向对象的做法
将逻辑内聚到领域对象中
@Data public class User { private Long id; private String name; private Integer age; private String password; public void changeInfo(String name, Integer age, String password) { this.name = name; this.age = age; this.password = getMd5(password); } private String getMd5(String password) { return password + "-md5"; // 模拟 } }
减少胶水代码,更易复用
public class UserService { @Autowired private UserGateway gateway; public void changeInfo(Long id) { User user = gateway.get(id); user.changeInfo("张三", 18, "12345"); gateway.save(user); } }
领域对象与数据对象
- 领域对象和数据对象为什么分开?为什么不合在一起,写个充血的数据对象,当做领域模型?
职责单一,各司其职,更利于维护
代码实例
领域对象中,只需要处理好自己的逻辑
@Data public class User { private Long id; private String name; private List<String> roles; // 权限列表 public User(String name) { this.name = name; this.roles = new ArrayList<>(); } public void addRole(String role) { this.roles.add(role); } }
在数据对象中,考虑如何存储,如"roles"可以用不同方式存储
- json字符串
- ","逗号隔开的字符串
- 一对多的关联表
// 数据对象 @Data @TableName("user") public class UserDO { @TableId(type = IdType.AUTO) private Long id; private String name; private String rolesJson; // 转换为json字符串 }
领域对象和数据对象间使用转换器执行转换
- 可使用"MapStruce"和"FastJson"实现
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING) public interface UserConvertor { @Mapping(target = "rolesJson", expression = "java(map(entity.getRoles()))") UserDO toDataObject(User entity); @Mapping(target = "roles", expression = "java(map(dataObject.getRolesJson()))") User toEntity(UserDO dataObject); default String map(List<String> roles) { return JSON.toJSONString(roles); } default List<String> map(String rolesJson) { return JSON.parseArray(rolesJson, String.class); } }
- 当业务拓展时,Role需要增加字段做更多功能,用户表里的roles由Json变更为Role子数据表
这样的设计能够尽可能减少代码修改
反例
如果省略领域模型,直接将数据模型写成充血模型
- 好消息:减少代码量,减少类
- 坏消息:不好维护,屎山代码
@Data @TableName("user") public class UserEntity { @TableId(type = IdType.AUTO) private Long id; private String name; @TableField(exist = false) private List<String> roles; // 字段不映射数据表 private String rolesJson; // 存储字段 public UserEntity(String name) { this.name = name; this.roles = new ArrayList<>(); this.rolesJson = "[]"; } public void addRole(String role) { this.roles.add(role); this.rolesJson = JSON.toJSONString(this.roles); } }
client
- client层主要用于微服务架构
非常适合与Dubbo搭配使用
client接口定义
client层的api中编写服务接口
public interface UserServiceI{ // 略 }
cleint打包发布私有Maven
- pom.xml
设置Maven私有仓库(Nexus3)配置
<dependencies>...略</dependencies> <build>...略</build> <distributionManagement> <repository> <id>maven-releases</id> <name>maven-releases</name> <url>${这里填写从nexus页面上复制的maven-releases的url}</url> </repository> <snapshotRepository> <id>maven-snapshots</id> <name>maven-snapshots</name> <url>${这里填写从nexus页面上复制的maven-snapshots的url}</url> </snapshotRepository> </distributionManagement>
- maven-settings.xml
私有仓库配置
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd"> <servers> <server> <id>maven-releases</id> <username>admin</username> <password>${密码}</password> </server> <server> <id>maven-snapshots</id> <username>admin</username> <password>${密码}</password> </server> </servers> </settings>
- deploy.sh
- maven打包脚本
使用maven的容器镜像,执行打包脚本
# 复制maven配置文件 cp maven-settings.xml /usr/share/maven/conf/settings.xml # 执行maven mvn deploy -pl cola-springboot-demo-client -am
app层接口实现
- app层,编写实现类
注册为Dubbo服务
@Service @DubboService // 注册为Dubbo服务 public class UserServiceImpl implements UserServiceI{ // 略 }
其他微服务RPC调用
其他项目从私有Maven仓库中加载client的接口及入参出参
<dependency> <groupId>com.xxc</groupId> <artifactId>cola-springboot-demo-client</artifactId> <version>1.0.0</version> </dependency>
在需要的地方调用,如
- App层的Executor调用
- infrastructure层的网关实现类中调用
@Component public class XxxExe{ @DubboReference private UserServiceI userService; public void execute(){ // 略 } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。