1. centos swapoff -a命令
swapoff -a 是一个 禁用所有 swap 分区/文件 的命令。
swap 是 Linux 的虚拟内存机制:当物理内存不够用时,系统会把一部分内存数据写到磁盘的 swap 分区(或 swap 文件)里,相当于“硬盘模拟内存”。 和Windows 的“虚拟内存(Pagefile)”原理上是类似。但是:
- swap 会 降低性能(因为磁盘比内存慢得多)。
- 在容器化环境、K8s、数据库等场景中,swap 经常被禁用,以防止不可控的性能抖动。
2. ddd模式开发中,为什么基础设施层的 DO 不建议用 @Data?
在 DDD(领域驱动设计)模式中,基础设施层的数据库对象(DO),主要职责是数据的存取与转换,不承载任何业务逻辑,优先使用 @Getter @Setter,而不是@Data。
@Data 的含义:Lombok 的 @Data 注解 =@Getter + @Setter + @RequiredArgsConstructor + @ToString + @EqualsAndHashCode
DDD场景下语义有点重,能减轻一点就减轻一点。
3. idea生成的serialVersionUID 是怎么生成的,是随机数吗
在 Java 中,serialVersionUID 是用于 Java 对象序列化版本控制 的一个唯一标识符。它的默认值是由 JDK 的 serialver 工具 或 JVM 在运行时根据类的结构(字段、方法、修饰符等)计算出来的。IDEA 的生成方式与 serialver 工具一致,遵循以下逻辑:将类的结构信息做签名哈希,生成一个固定的 long 值。
建议直接用 1L, 而不是 IDEA 生成的那串 hash。
-
手动维护序列化版本更清晰
-
避免因自动生成导致版本飘变
-
大多数企业级项目/框架都这么做
4. self-explaining-自解释性
类名、方法名、字段名,都要语义明确。
好代码应该像一本读得通顺的小说,而不是一本需要翻字典的谜语集。
self-explaining 是代码质量的第一层,也是团队协作效率的保障。
5. DDD项目中 使用 Optional 的位置
层级
是否推荐使用 Optional
说明
Repository 层
推荐返回 Optional
明确表达:查不到对象可能为 null,Optional 是语义清晰的替代方案。
Domain 层
尽量避免传递 Optional
领域模型不关心 Optional,应处理为 Null Object、异常或业务决策。
ApplicationService 层之间调用
不推荐返回 Optional
应明确是存在还是不存在,内部做好处理,不要把“不确定性”传递出去。
Controller 层
不建议返回 Optional
接口层应返回标准响应体结构,如 ApiResult,对“无结果”有统一处理。
6. @Nonnull加在接口上还是实现方法上?
都加。那为什么不只加在实现类?
- 接口是对外的能力声明(即契约),调用方只看到接口,不知道实现,要让调用方看到 。
- @Nonnull加在接口上,IDE/静态分析工具(如 IntelliJ、Sonar)才会高亮提示“永远不为 null”;
7. 题外话
你知道隆达新桥吗?一座把监狱建在桥中央、把城市分裂在峡谷两岸的西班牙奇迹。
站在桥上,你看见的不只是建筑,而是历史、权力和地理共同撕开的地表。
8. DDD中,参数的校验应该在哪做?在Application service中可以做,在Domain-Factory构建对象的时候也可以做
一句话核心原则:
“是否和领域业务语义相关”,决定校验逻辑是否进入 Domain 层。与业务说话的进 Domain,和接口打交道的留在外头。
问题的核心不是“在哪里都可以做”,而是“做这件事的语义归谁”
类型
示例
应放位置
原因
领域规则校验
用户是否有发布权限、时间是否合理
Domain(Entity/Factory)
这是业务本身的一部分,决定行为是否合法
构造合法聚合根的条件
类别是否存在、金额是否超限
Domain(Factory)
聚合根必须是合法的业务对象
上下文一致性校验
当前用户是否归属某商户
ApplicationService
和调用者相关,不属于领域本身
防御性参数校验
判空、长度、格式、手机号是否合法
DTO或 AppService
跟业务语义无关,只是接口层的输入检查
Bonus:怎么判断一个规则是不是“业务规则”?
- 是否跟具体业务场景(发布职位、投递简历)强绑定?
- 是否会影响领域行为(发布、编辑、撤回等)的成立?
- 是否可作为领域模型约束的一部分?
如果答案是“是”,那么它就是业务规则,应当进到 Domain。
9. domain service 能否注入其他 Bean?
可以注入,但要分清楚依赖的“性质”:
注入的 Bean 类型
是否允许
原因/建议
Domain Object / Repository
✅
合法领域依赖,例如查用户套餐
Domain Service(协同)
✅
多个领域服务组合逻辑
QueryApi(只读服务)
⚠️ 可用,但需封装抽象
读模型是外部依赖,应通过接口/适配层屏蔽
CommandApi(带副作用)
❌ 避免
domain service 应尽量纯粹,不直接引入副作用调用
第三方服务 / 客户端
❌ 绝不
属于 infrastructure 层依赖,破坏领域封装性
话是这么说,真做起来QueryApi哪有时间做适配。都是直接注入。
10. 给第三方出接口,一定要加业务唯一id 和 请求唯一id
对接的某个公司就只有一个请求唯一id,用来做防重放,简直是灾难级别的接口设计。
目的
字段
作用
幂等
业务唯一ID
保证“相同业务”不会被重复处理,比如重复提现
防重放
请求唯一ID
防止同一个请求被拦截/篡改后重复投递(重放攻击)
11. 策略模式的核心价值——在运行时可替换的行为抽象
-
如果一种业务逻辑在不同情况下可以切换实现(比如支付渠道、排序算法、折扣计算方式),那么策略模式就能帮你把变化点独立出来,降低耦合。
-
如果业务逻辑是硬编码规则(例如佣金结算单只能众腾开票,其他都必须百旺),那就没有动态替换的需求,抽策略反而是自找麻烦。这种固定映射更适合用 if/else 或 switch + Factory/Service 定向调用,而不是策略模式。因为未来要改成“可替换”概率很低,它只是一个路由决策,不是一个可变行为点。
12. 领域行为
Domain Behavior,领域对象自己提供的、与它业务职责相关的动作(方法),并且会修改自己状态或者返回一个新对象。
领域行为的几个特征
-
发生在领域对象内部
-
围绕业务概念
-
隐藏实现细节
-
保证领域不变量
总结
- 领域行为 = 领域对象自己提供的、能代表业务语义的动作方法
- 发生在领域对象内部
- 负责维护业务规则和不变量
- 能避免应用层直接改内部状态
13. public AuthWrappedRequestDTO 前后两个T各自的作用
1. 方法前面的
2. 方法返回类型的 AuthWrappedRequestDTO
所以,前后两个 T 其实都是同一个泛型类型,前面是声明,后面是使用。
14. List的话不返回Optional,单个查询返回optional
单对象查询 → Optional。避免了返回 null,减少了 NullPointerException 的风险。
多对象查询 → List,不包Optional,返回Collections.emptyList() 或 new ArrayList<>(),空列表()天然表示“没有结果”,无需额外包装。
15. MyBatis-Plus list返回结果直接stream
MyBatis-Plus 的 list() 返回的永远是 非 null 的 List(底层已经做了 Collections.emptyList() 处理)。
所以你不需要担心 list() 返回 null,直接 .stream() 是安全的。
MyBatis 自身的 ResultHandler 机制保证了 List 一定是非 null。
16. 查询方法命名
Controller / Service 层:更常用 getXxx 或 queryXxx,因为对外暴露接口,语义要直观。
Repository/Dao 层:多用 findBy...,贴近数据库语义。
17. 什么是应用编排,什么是领域逻辑?
if 判断的结果是否改变业务合法性?
if 判断依赖的是领域模型还是外部上下文?
18. Spring Modulith 注解 @NamedInterface
Spring Modulith 是 Spring 团队在近几年推出的一个框架,用来支持 模块化单体应用(Modular Monolith) 的开发。它的目标是让一个大的 Spring Boot 应用可以被拆分成内部模块(类似“bounded context”),并且在代码层面 enforce(约束)模块之间的依赖关系。
在 Spring Modulith 里,每个 package 都可以看作一个模块。而模块对外暴露哪些 API(哪些包能被外部依赖),就需要通过 @NamedInterface 来标注。
@NamedInterface 的作用:如果别的模块想要依赖你这个模块,只能依赖你 @NamedInterface("xxx") 标记的包。没有标注的包(比如 domain、internal)在概念上属于模块的“实现细节”,外部模块不应该直接引用。
19. factory 不依赖外部系统
Factory 可以做校验,但前提是 只涉及构建对象所需的内部规则。
如果校验需要依赖外部系统(API、Repository),那它就超出了 Factory 的职责,应该在 Application Service里做。
换句话说,Factory 接收的参数必须已经是“干净”的,外部数据准备、跨边界的校验,应该在应用层解决。
20. DDD Infrastructure 层职责
-
技术资源适配
-
外部系统调用适配
这些在 infra 层里通常以 Client/Adapter 的形式存在,例如:
public interface OrderQueryPort {
OrderInfoDTO findByOrderNum(String orderNum);
}
@Component
@RequiredArgsConstructor
public class OrderQueryApiAdapter implements OrderQueryPort {
private final OrderQueryApi orderQueryApi;
@Override
public OrderInfoDTO findByOrderNum(String orderNum) {
return orderQueryApi.orderInfoByOrderNum(orderNum);
}
}
然后 domain/application 依赖的是 OrderQueryPort 接口,不直接依赖 Feign 或 Dubbo API。
-
解耦:domain/application 不知道你到底是调用 Feign、Dubbo 还是 mock,本地单测时可以直接替换。
-
隔离变化:外部 API 签名、DTO 改了,只动 infra 层,不动 domain/application。
-
统一规范:所有外部交互(无论数据库还是远程 API)都在 infra,代码更清晰。
21. 订单和业务收入类型挂钩,业务收入类型和发票挂钩
业界主流做法就是 “订单 → 收入类型 → 可开票种类” 这条链路。订单不直接决定开什么票,而是通过业务收入类型来决定。
为什么这样挂钩?
订单本身是交易事实,但税务系统不关心“你卖了个套餐还是抽了佣金”,它关心的是:这笔收入属于哪个税收分类编码。
所以要通过 业务收入类型(Revenue Type) 来做中间层。
这样你不用在每个订单里直接硬编码“发票内容”,而是通过配置来映射。