- 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 -amapp層接口實現
- 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(){ // 略 } }