云巧组件如何实现代码架构设计可视化

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 在项目搭建完成进行了N个迭代之后,往往因为需求的变化以及设计的缺陷导致领域模型、接口、数据库设计等和最开始的时候大为不同,架构设计需要保鲜会花去大量的时间。有没有一种办法可以实时反应项目的各种技术设计呢?就像Swagger一样,代码自动生成文档。我们采用了静态代码扫描的方案,通过代码来反应真实的技术设计,这就是《云巧工坊-应用素描》的功能。

在项目搭建完成进行了N个迭代之后,往往因为需求的变化以及设计的缺陷导致领域模型、接口、数据库设计等和最开始的时候大为不同,架构设计需要保鲜会花去大量的时间。有没有一种办法可以实时反应项目的各种技术设计呢?就像Swagger一样,代码自动生成文档。我们采用了静态代码扫描的方案,通过代码来反应真实的技术设计,这就是《云巧工坊-应用素描》的功能。

《应用素描》提供了领域模型、数据模型、接口信息的详细信息查看功能,还提供了模型与模型之间的关系,表与表之间的关系图,是一个快速了解现有项目设计的好帮手。

使用方式

一、项目引入

<dependencies>    ...
<dependency><groupId>com.aliyun.gts.yunqiao</groupId><artifactId>yunqiao-boot-starter-arch-annotation</artifactId><version>${yunqiao-boot.version}</version></dependency>    ...
</dependencies>x



二、注解使用

2.1 领域模型注解

根据 领域驱动开发的理论(DDD),领域模型分为3中类型:

  1. ValueObject(值对象):没有唯一标识只是代表一些列属性的对象,比如
importcom.aliyun.gts.yunqiao.arch.annotation.domain.ValueObject;
/*** 表示一个点*/@ValueObjectpublicclassPoint {
/*** x 坐标*/privatedoublex;
/*** y 坐标*/privatedoubley;
}
  1. Entity(实体):有唯一标识,可以根据唯一标识获取到的唯一的对象,比如
importcom.aliyun.gts.yunqiao.arch.annotation.domain.Entity;
/*** 地址*/@Entity(identity="addressCode")
publicclassAddress {
/*** 地址编码*/privateStringaddressCode;
/*** 省*/privateStringprovince;
/*** 市*/privateStringcity;
/*** 区*/privateStringarea;
}
  1. Aggregate(聚合根):聚合根是一种特殊的实体,它除了有唯一标识,还聚合了很多其他实体和值对象,相当于数据库表中的主表,比如
importcom.aliyun.gts.yunqiao.arch.annotation.domain.Aggregate;
/*** 用户*/@Aggregate(identity="userId")
publicclassUser {
/*** 用户ID*/privateStringuserId;
/*** 用户名*/privateStringname;
/*** 年龄*/privateintage;
/*** 用户住址*/privateAddressaddress;
}
  1. Context(限界上下文):把高内聚相关的一些聚合根、实体、值对象划分到一起的一种分类,一般在java里就是一个package(包)。
// package-info.java@Context(code="user", name="用户域")
packagecom.aliyun.gts.x.user;
importcom.aliyun.gts.yunqiao.arch.annotation.domain.Context;
  1. DomainService(领域服务):把不太适合在领域模型中编写的,但又和领域模型相关的一些方法放到独立的对象中,称之为领域服务,在贫血模型中,所有方法都是在领域服务中的,比如:
importcom.aliyun.gts.yunqiao.arch.annotation.domain.DomainService;
/*** 用户领域服务*/@DomainService(User.class)
publicclassUserDomainService {
/*** 创建用户*/publicUsercreateUser(...) {...}
}
6.DomainRepository(领域仓储):持久化领域模型的对象,一般为数据库操作对象,称之为领域仓储,比如importcom.aliyun.gts.yunqiao.arch.annotation.domain.DomainRepository;
/*** 用户领域仓储*/@DomainRepository(User.class)
publicinterfaceIUserDomainRepository {
/*** 保存用户*/voidsave(Useruser);
}



把 yunqiao-boot-starter-arch-annotation 引入项目后,就可以使用它提供的注解对领域模型进行标记,上面示例中的

  • @ValueObject 对值对象进行标记
  • @Entity(identity="") 对实体进行标记,其中 identity 标识该实体的唯一标识的属性名称
  • @Aggregate(identity="") 对聚合根进行标记,其中 identity 标识该实体的唯一标识的属性名称
  • @Context(code="", name="") 在package-info.java文件中对package进行标记,其中code为该限界上下文的唯一标识,name为该限界上下文的名称。
  • @DomainService(value=Class) 对领域服务进行标记,其中value为聚合根的类,表示该服务为哪一个聚合根服务。
  • @DomainRepository(value=Class) 对领域仓储进行标记,其中value为聚合根的类,表示该仓储为哪一个聚合根进行持久化操作。

2.2 数据模型注解

复用 Mybatis-Plus 的 @TableField、@TableId、@TableName 用来标记 Data Object。除此之外,添加了以下注解,以更全面的描述数据模型的结构。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited@Documentedpublic@interfaceTableExt {
Index[] indexes() default {};
PrimaryKeyprimaryKey() default@PrimaryKey(columns= {});
Stringcharset() default"utf8";
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited@Documentedpublic@interfaceTableFieldExt {
booleanunique() defaultfalse;
booleannotNull() defaultfalse;
booleanautoIncrement() defaultfalse;
StringdefaultValue() default"";
intlength() default-1;
}
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public@interfaceIndex {
IndexColumn[] columns();
Stringname();
booleanunique() defaultfalse;
}
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public@interfacePrimaryKey {
IndexColumn[] columns();
}
@Target({})
@Retention(RetentionPolicy.RUNTIME)
public@interfaceIndexColumn {
enumIndexColumnOrder {
UNDEFINED,
ASC,
DESC,
    }
Stringname();
IndexColumnOrderorder() defaultIndexColumnOrder.UNDEFINED;
intlength() default-1;
}

Example

@TableExt(charset="gb2312", primaryKey=@PrimaryKey(
columns=@IndexColumn("id")
),
indexes= {
@Index(name="idx_1", columns=@IndexColumn("field1")),
@Index(name="uk_1", columns= {@IndexColumn(value="field2", length=100),
@IndexColumn(value="field1", order=IndexColumn.IndexColumnOrder.DESC)})
    })
@TableName(value="tableName", schema="schemaName")
publicclassMybatisPlusDataObject {
privatestaticfinalStringDUMMY="DUMMY";
@TableId(value="ID", type=IdType.AUTO)
privateLongid;
@TableField(exist=false)
privateStringnotExistField;
@TableField@TableFieldExt(unique=true, notNull=true, autoIncrement=true, defaultValue="1234", length=1024)
privateStringfield1;
@TableField("the_second_field")
privateStringfield2;
}


2.3 其他支持的注解

控制器(Rest API)标记

兼容 Spring MVC。通过 @Controller 或 @RestController 标记类是一个控制器类;通过 @RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping,标记方法是一个对外的 API。

AppService 标记

通过 @AppService 标记类是一个应用服务类(此注解继承了 Spring 的 @Service 注解,故无需再重复使用 Spring 的注解);应用服务类下所有的 public 方法为应用服务的行为。

Mapper 标记

复用 Mybatis-Plus 的 Mapper<T> 接口(BaseMapper 扩展了 Mapper),用以标记 mapper 以及其服务的数据模型;mapper 接口的所有方法为 mapper 的行为。


实现原理

Java语法解析使用的是开源库 javaparser,javaparser 可以把Java源代码解析成一颗语法树,然后提供各种回调接口来有序遍历这棵树。例如遍历一个文件里所有定义的类和获取类里面的方法定义:

voiditerateClassOrInterface(CompilationUnitcompilationUnit) {
compilationUnit.accept(newVoidVisitorAdapter<Void>() {
@Overridepublicvoidvisit(ClassOrInterfaceDeclarationn, Voidarg) {
super.visit(n, arg);
List<MethodDeclaration>methods=c.getMethods();
            }
    }, null);
}

javaparser 解析一个文件成为语法树是非常消耗性能的,所以不能频繁的去调用 parse 方法去解析文件,但是也不能把所有的语法分析逻辑写在一个回调里,那么就非常适合使用责任链模式来对不同业务的分析逻辑进行解耦

最后把解析后的结构化数据交给前端页面进行可视化渲染展示,就可以实现代码即文档了。

目录
相关文章
|
2月前
|
监控 网络协议 Java
Tomcat源码解析】整体架构组成及核心组件
Tomcat,原名Catalina,是一款优雅轻盈的Web服务器,自4.x版本起扩展了JSP、EL等功能,超越了单纯的Servlet容器范畴。Servlet是Sun公司为Java编程Web应用制定的规范,Tomcat作为Servlet容器,负责构建Request与Response对象,并执行业务逻辑。
Tomcat源码解析】整体架构组成及核心组件
|
16天前
|
负载均衡 5G 网络性能优化
深入解析LTE(长期演进技术)的基本架构及其关键组件
深入解析LTE(长期演进技术)的基本架构及其关键组件
81 2
|
2月前
|
Kubernetes API 调度
Kubernetes 架构解析:理解其核心组件
【8月更文第29天】Kubernetes(简称 K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用。它提供了一个可移植、可扩展的环境来运行分布式系统。本文将深入探讨 Kubernetes 的架构设计,包括其核心组件如何协同工作以实现这些功能。
102 0
|
1天前
|
设计模式 人工智能 算法
编程之旅:从代码到架构的感悟
【9月更文挑战第33天】在编程的世界里,代码不仅是实现功能的工具,更是连接思想与现实的桥梁。本文将通过个人的编程经历,分享从编写第一行代码到设计系统架构的旅程,探索编程背后的哲学和技术演变。我们将一起思考,如何在代码的海洋中找到自己的航向,以及在这个过程中如何不断成长和适应变化。
|
23天前
|
机器学习/深度学习 测试技术 数据处理
KAN专家混合模型在高性能时间序列预测中的应用:RMoK模型架构探析与Python代码实验
Kolmogorov-Arnold网络(KAN)作为一种多层感知器(MLP)的替代方案,为深度学习领域带来新可能。尽管初期测试显示KAN在时间序列预测中的表现不佳,近期提出的可逆KAN混合模型(RMoK)显著提升了其性能。RMoK结合了Wav-KAN、JacobiKAN和TaylorKAN等多种专家层,通过门控网络动态选择最适合的专家层,从而灵活应对各种时间序列模式。实验结果显示,RMoK在多个数据集上表现出色,尤其是在长期预测任务中。未来研究将进一步探索RMoK在不同领域的应用潜力及其与其他先进技术的结合。
64 4
|
27天前
|
XML Java 数据库
在微服务架构中,请求常跨越多个服务,涉及多组件交互,问题定位因此变得复杂
【9月更文挑战第8天】在微服务架构中,请求常跨越多个服务,涉及多组件交互,问题定位因此变得复杂。日志作为系统行为的第一手资料,传统记录方式因缺乏全局视角而难以满足跨服务追踪需求。本文通过一个电商系统的案例,介绍如何在Spring Boot应用中手动实现日志链路追踪,提升调试效率。我们生成并传递唯一追踪ID,确保日志记录包含该ID,即使日志分散也能串联。示例代码展示了使用过滤器设置追踪ID,并在日志记录及配置中自动包含该ID。这种方法不仅简化了问题定位,还具有良好的扩展性,适用于各种基于Spring Boot的微服务架构。
31 3
|
2月前
|
存储 安全 虚拟化
深入解析:Docker的架构与组件
【8月更文挑战第27天】
132 5
|
2月前
|
XML 开发框架 .NET
.NET框架:软件开发领域的瑞士军刀,如何让初学者变身代码艺术家——从基础架构到独特优势,一篇不可错过的深度解读。
【8月更文挑战第28天】.NET框架是由微软推出的统一开发平台,支持多种编程语言,简化应用程序的开发与部署。其核心组件包括公共语言运行库(CLR)和类库(FCL)。CLR负责内存管理、线程管理和异常处理等任务,确保代码稳定运行;FCL则提供了丰富的类和接口,涵盖网络、数据访问、安全性等多个领域,提高开发效率。此外,.NET框架还支持跨语言互操作,允许开发者使用C#、VB.NET等语言编写代码并无缝集成。这一框架凭借其强大的功能和广泛的社区支持,已成为软件开发领域的重要工具,适合初学者深入学习以奠定职业生涯基础。
90 1
|
2月前
|
JSON 前端开发 API
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
47 2
|
2月前
|
JSON 数据可视化 数据格式
【Azure 环境】中国区Azure是否可以根据资源组的模板,生成一个可视化的架构图呢?
【Azure 环境】中国区Azure是否可以根据资源组的模板,生成一个可视化的架构图呢?
【Azure 环境】中国区Azure是否可以根据资源组的模板,生成一个可视化的架构图呢?
下一篇
无影云桌面