别再什么类都写 public 了!教你用 4 道防线锁死 Java 代码边界

发布时间:2026/9/28 19:06:13

别再什么类都写 public 了!教你用 4 道防线锁死 Java 代码边界
️ Java 访问控制全景指南从代码微观到物理宏观的四道防线 故事背景我们正在开发一个电商的订单模块Order Module。这个模块的核心任务是接收订单数据。校验金额与库存。计算折扣并保存到数据库。调用外部的支付模块Payment Module进行扣款。如果缺乏控制团队成员可能会直接去 new 别人的内部校验类、甚至直接调用底层的数据库连接导致架构瞬间崩塌。下面我们用四道防线把这个系统治理得井井有条。️ 第一道防线成员级别Class Member Level—— 守护类内部的“神经末梢”这是最细粒度的控制。它的目的是隐藏类内部的私有状态防止外部通过“乱改属性”导致程序崩溃。 业务场景在订单实体类Order中订单金额totalAmount和订单状态status是非常敏感的数据绝不能让外部直接用赋值。 代码实现packagecom.shop.order.domain;publicclassOrder{// private对外部绝对隐藏只有类内部的方法能改privatedoubletotalAmount;privateStringstatusPENDING;publicOrder(doubletotalAmount){if(totalAmount0){thrownewIllegalArgumentException(订单金额必须大于0);}this.totalAmounttotalAmount;}// 只暴露只读窗口publicdoublegetTotalAmount(){returnthis.totalAmount;}// 外部只能通过业务方法修改状态无法直接 order.status SUCCESSpublicvoidmarkAsPaid(){if(!PENDING.equals(this.status)){thrownewIllegalStateException(当前状态无法支付);}this.statusPAID;}}防线效果外部代码只能调用order.markAsPaid()如果外部尝试直接操作order.status SUCCESS编译期就会直接报错。 第二道防线包级访问权限Package-Private Level—— 打造包内“黑盒”这是日常业务开发中最重要、但最容易被忽略的防线。它的目的是让一个包Package内只有唯一一个类代表对外出口其他辅助类全部隐姓埋名。 业务场景在com.shop.order.service包下我们有核心的订单服务类、一个复杂的金额计算类、一个安全校验类。我们只希望外部知道“订单服务”不想让他们看到计算和校验的细节。 代码实现 目录结构src/com/shop/order/service/ ├── OrderService.java -- 唯一公开出口 (public) ├── AmountCalculator.java -- 包级私有 (不加 public) └── OrderValidator.java -- 包级私有 (不加 public)1. 公开出口类packagecom.shop.order.service;importcom.shop.order.domain.Order;publicclassOrderService{// 注意有 publicpublicvoidprocessOrder(Orderorder){// ✅ 同一个包内可以自由调用没有 public 的类OrderValidatorvalidatornewOrderValidator();AmountCalculatorcalculatornewAmountCalculator();validator.validate(order);calculator.calculateDiscount(order);System.out.println(订单处理成功);}}2. 隐藏的内部零件金额计算类packagecom.shop.order.service;importcom.shop.order.domain.Order;// 注意前面没有写 public它是包级私有的classAmountCalculator{voidcalculateDiscount(Orderorder){// 方法也没有写 publicSystem.out.println(正在执行复杂的折扣计算逻辑...);}}❌ 外部包滥用时的效果如果有别的团队成员在com.shop.user包下尝试调用计算器packagecom.shop.user;// import com.shop.order.service.AmountCalculator; // ❌ 编译直接报错无法导入publicclassUserService{publicvoidtest(){// ❌ 编译期报错AmountCalculator is not public in com.shop.order.service. Cannot be accessed from outside package// AmountCalculator calc new AmountCalculator();}}防线效果外部同学在敲代码时代码补全提示里只会干净地出现OrderService。内部的AmountCalculator被完美隐藏你可以随时重构它的代码哪怕把它删了换个名字也绝不会影响到外部任何一行代码。 第三道防线Java 9 模块化系统JPMS—— 设立大业务板块的“海关”当项目变大后包级权限有个致命漏洞防君子不防小人。如果别人在别的工程里故意创建了一个一模一样的包名com.shop.order.service他就能够强行 new 你的AmountCalculator。为了彻底锁死大边界我们需要 JPMS。 业务场景我们将整个订单系统打包成一个独立的模块com.shop.order.module。我们要求即使有些类在包里必须声明为public但只要没有经过我“海关”的允许外界连碰都别想碰。 代码与配置实现 目录结构order-module/ └── src/ └── main/ └── java/ ├── module-info.java -- 模块海关配置文件 └── com/shop/order/ ├── domain/Order.java └── internal/CoreEngine.java -- 核心引擎必须跨包但不想对外暴露1. 编写海关配置module-info.javamodulecom.shop.order.module{// 明确放行只把外部需要的域模型包导出去exportscom.shop.order.domain;// ❌ 不写 exports com.shop.order.internal;// 意味着 internal 包下的所有 public 类出了这个模块全变废纸}2. 模块内的核心引擎在 internal 包下packagecom.shop.order.internal;publicclassCoreEngine{// 注意虽然它是 publicpublicvoidexecuteSecretAlgorithm(){System.out.println(订单系统的核心机密算法正在运行...);}}❌ 外部模块如支付模块调用时的效果如果外部的com.shop.payment模块尝试强行调用packagecom.shop.payment;// 即使 CoreEngine 是 public 的因为所在的包没被 exportsimportcom.shop.order.internal.CoreEngine;// ❌ 编译期直接被 JVM 海关拦下报错Package com.shop.order.internal is not exported by module com.shop.order.modulepublicclassPaymentService{publicvoidpay(){// CoreEngine engine new CoreEngine(); // ❌ 绝对无法通过编译}}防线效果建立了极度安全的底层防御。即便黑客通过反射Reflection强行获取在没有opens关键字的情况下运行时也会直接抛出InaccessibleObjectException。 第四道防线多模块物理拆分Build Tools—— 彻底切断源头依赖这是企业级大厂最普遍采用、最铁血的手段。它的逻辑是在你的构建工具Maven/Gradle里根本不给你引入对方的 Jar 包。巧妇难为无米之炊没引入 Jar 包你连对方的名字都打不出来。 业务场景在电商系统里我们严禁支付模块Payment Module反向调用订单模块Order Module因为这会导致可怕的循环依赖订单调支付支付又调订单项目直接无法编译。 Maven 配置实现我们把项目物理拆分为两个独立的文件夹两个独立的 Maven Project1. 订单模块的pom.xmlorder-system订单系统需要调用支付所以它声明了依赖groupIdcom.shop/groupIdartifactIdorder-system/artifactIdversion1.0.0/versiondependencies!-- 引入支付系统的 Jar 包 --dependencygroupIdcom.shop/groupIdartifactIdpayment-system/artifactIdversion1.0.0/version/dependency/dependencies2. 支付模块的pom.xmlpayment-system支付系统是独立、高冷的。它的pom.xml里绝对不写任何关于order-system的依赖。groupIdcom.shop/groupIdartifactIdpayment-system/artifactIdversion1.0.0/versiondependencies!-- 绝对不加 order-system 的依赖 --/dependencies❌ 铁血效果如果某个新人在编写PaymentService.java时脑子一热想去调用订单packagecom.shop.payment;publicclassPaymentService{publicvoidprocessPayment(){// ❌ 敲下这句话的瞬间IDEA 直接飘红代码彻底报废// 因为 payment-system 的类路径Classpath里压根没有订单的类com.shop.order.service.OrderServiceservice;}}防线效果从物理层面切断了错误的架构设计。除非去改pom.xml否则程序员无论动用什么黑科技不管是反射、冒充包名还是改修饰符在编译期都绝对无法调用订单模块。 终极战术总结架构师如何打出这套组合拳在实际的大型项目研发中顶级的技术架构师绝不依赖单一防线而是将它们层层嵌套宏观物理隔离第四道先用 Maven/Gradle 拆分大业务。payment不能依赖order从源头掐断不良设计的苗头。大边界海关第三道在被允许依赖的路径上例如order依赖payment通过 JPMS (module-info.java) 规定哪些是公共 SDK 包哪些是内部包防止底层的CoreEngine被乱用。日常代码黑盒第二道在同一个子模块内部写业务代码时大量使用包级访问权限不加public。每个功能包只留一个核心类作为对外的public窗口其余小零件全部在包内消化。属性微观保护第一道在具体的实体类里把核心数据用private锁死只通过有业务含义的方法暴露修改入口。通过这四道防线的层层围剿你的 Java 系统就能在面对几百人团队协作时依然保持教科书级的、清爽完美的架构结构

相关新闻

Notion PRD 模板 2024:3步构建动态需求文档,支持Jira与Confluence联动

Notion PRD 模板 2024:3步构建动态需求文档,支持Jira与Confluence联动

2026/9/7 7:38:54

Notion PRD 2024:打造动态需求文档的3个关键步骤与Jira/Confluence无缝联动在2024年的敏捷开发环境中,传统静态PRD文档已经无法满足快速迭代的需求。作为一位每周需要处理5-8个需求迭代的产品负责人,我发现Notion的数据库特性结合自动化工作流…

分支循环知多少

分支循环知多少

2026/8/30 16:15:59

分支1. 条件判断基础在编程中,分支结构用于根据条件决定是否执行特定的代码块。Python 中使用 if 语句来实现条件判断。if语句的写法如下我们知道Python 中是严格要求缩进的,写完 if 条件 :后在 “ :” 后按回车,光标…

2026 舰载无人机驻训的深蓝蜕变

2026 舰载无人机驻训的深蓝蜕变

2026/8/27 14:31:12

海风为伴,甲板为营。2026年盛夏,鹰览舰载无人机操作手常文宝,完成了一场从“陆地飞手”到“舰载尖兵”的硬核蜕变。当陆地经验遭遇海洋法则,鹰览人用实训的汗水与坚守,重新定义了一名新时代海防飞手的使命担当。 劈波斩…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/28 4:08:17

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/28 16:01:49

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/28 3:14:54

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/28 3:47:14

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/28 16:01:48

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/28 5:05:21

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/28 16:01:48

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…