COLA各模块理解
-
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(){
// 略
}
}