Java 在大型程序中管理隐私

Java 在大型程序中管理隐私,java,packages,privacy,factories,Java,Packages,Privacy,Factories,我正在为这种结构的机器人技术开发一个程序(我将包括图层的功能,只是为了好玩): 层A-GUI处理按钮、操纵杆等的简单界面。将这些值转换为命令发送到控制界面 层B-控制评估来自数据库的设备读/写条目和来自gui的命令请求,以便为数据库计算新的设备写条目 层C-数据库设备的逻辑表示,创建从设备写入和读取的值的历史记录 D层-硬件与物理硬件对话。将设备写入条目转换为命令并将其发送到设备。使用来自设备的值更新数据库设备读取条目 我想创建一个java应用程序,在这个应用程序中,任何层都不能调用它上面或

我正在为这种结构的机器人技术开发一个程序(我将包括图层的功能,只是为了好玩):

  • 层A-GUI处理按钮、操纵杆等的简单界面。将这些值转换为命令发送到控制界面

  • 层B-控制评估来自数据库的设备读/写条目和来自gui的命令请求,以便为数据库计算新的设备写条目

  • 层C-数据库设备的逻辑表示,创建从设备写入和读取的值的历史记录

  • D层-硬件与物理硬件对话。将设备写入条目转换为命令并将其发送到设备。使用来自设备的值更新数据库设备读取条目

我想创建一个java应用程序,在这个应用程序中,任何层都不能调用它上面或下面一层以上的函数


是否可以使用包隐私或类似工厂的模式创建项目结构,从而使层a中的代码无法从层D或层C导入任何内容

这不是仅使用访问修饰符就可以实现的

你也不能通过(某种方式)控制
import
。。。因为Java语言对导入没有任何(额外)限制。(import指令实际上只是一种语法糖,因此您不需要到处使用完全限定名。)

那你还能做什么呢

  • 您可以尝试实施运行时限制,以防止错误的层访问factory对象。但这些限制很容易被蓄意或意外颠覆

  • 您可以使用某种内部“能力”或“凭证”机制,但很难看到如何防止凭证泄漏。(如果凭据由安全管理器管理(请参见下文),这可能会起作用,但这会使问题更加复杂。)

我认为您可以做到这一点的唯一方法是实现一个定制的
SecurityManager
,并在每次有潜在的跨层调用时执行安全检查。例如,安全管理器可以(尽管代价高昂)检查调用堆栈以找到调用它的方法/类/包。您还需要关闭某些反射操作,这些操作可用于(普通地)破坏安全管理器。本质上,除了内环外,所有代码都需要被视为“不可信”代码

坦率地说,用具有“防黑客”安全性的JVM实现这种事情可能超出了普通人的能力。(Sun/Oracle尚未成功……)


其他备选方案包括:

  • 依靠程序员的纪律

  • 依靠代码库的静态分析;e、 g.借助于记录访问规则的注释。要做到这一点,您需要编写自己的代码分析器

  • 在层之间使用地址空间分隔和占用空间小、安全性高的API。(这里我们不再讨论单一的传统JVM…)


    • TL;DR.对于这一点,没有一个灵丹妙药解决方案,但可以利用许多不同的工具

      有各种不同的技术来隔离软件应用程序的不同部分,但我认为没有任何一种解决方案可以解决所有问题。一些生成系统可以限制目标之间的依赖关系(例如,在生成目标上有一个
      可见性
      属性,该属性可以防止一个目标依赖另一个目标,即使它们通过Java的类可见性彼此可见),该属性可以与Java的内置可见性结合使用。例如:

       // Foo.java
       package com.yourcompany.foo;
       public class Foo {}
      
       // Build rule for Foo.java
       java_library(
          name = "Foo",
          srcs = ["Foo.java"],
          # Restricts visibility to this directory, even though
          # the class visibility was "public" 
          visibility = ["//visibility:private"],
       )
      
       // Bar.java
       package com.yourcompany.bar;
      
       import com.yourcompany.foo.Bar; // prevented by build visibility system
      
       public class Bar {
          Foo foo = new Foo();
       }
      
      还可以使用接口来调解逻辑组件之间的所有交互,并隐藏这些接口的实现(例如,仅通过服务注册表接口或通过接口依赖项注入公开实现)。例如,使用,您可以为每个层创建一个单独的层,这将允许您编写如下代码:

      final class ControllerImpl implements Controller {
         // Since "ControllerImpl" is instantiated / wired into the
         // controller layer, the database dependency is available /
         // exposed for injection within this layer. The access control is
         // strictly performed by the way the dependencies are wired.
         @Inject
         public ControllerImpl(Database database) {
           // ...
         }
      }
      
      除上述内容外,您还可以使用依赖性分析/依赖性分析测试或提交挂钩来自动检测依赖性规则冲突(并触发错误/拒绝基于它们的提交)。例如,穷人的解决方案是简单地扫描每个文件以查找其包声明和导入语句,然后使用一些启发式方法来检测坏的依赖关系

      另一种方法是将不同的组件捆绑在单独的JAR中,并使用自定义的JAR加载它们,这将允许您使用反射防止非法访问(否则可能会绕过任何程序结构)

      除了自动化方法外,手动方法也有其价值。手动方法包括定期的代码审查和在这些代码审查和审核期间执行的策略


      简言之,没有一个正确的答案。有必要结合使用几种不同的方法,这取决于这种分离的重要性。

      刚才向Michael Aaron Safyan提出了相同的问题,但您认为这些昂贵/复杂的方法对于代码维护来说是否现实?或者程序员纪律是一条出路吗?如果您只关心代码的可维护性,那么程序员纪律就足够了。好的。如果只是为了整洁,而不是严格的隐私问题,那么通过接口、使用注入框架管理依赖项和手动规程来调节控制就足够了,特别是如果代码库的大小合理/可管理。但是,如果您还没有选择构建系统,我建议您使用Bazel(尽管我有点偏颇),如果您正在使用它,那么您可以使用它