管理大型程序中的隐私

时间:2015-07-19 00:55:37

标签: java packages privacy factories

我正在开发一个具有这种结构的机器人程序(我将包括这些层为笑而做的事情)

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

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

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

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

我想创建一个java应用程序,其中没有任何层能够调用上面或下面多层的函数。

是否可以使用软件包隐私创建项目结构,或者像工厂这样的模式使代码无法进入,比如说A层,从层D或C导入任何内容?

2 个答案:

答案 0 :(得分:3)

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

有许多不同的技术可以隔离软件应用程序的不同部分,但我认为没有任何一种解决方案可以解决所有问题。一些构建系统可以限制目标之间的依赖关系(例如Bazel在构建目标上具有visibility属性,可以阻止一个目标依赖另一个目标,即使它们通过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();
 }

还可以使用接口来调解逻辑组件之间的所有交互并隐藏这些接口的实现(例如,仅通过服务注册表接口或通过接口依赖性注入来暴露实现)。例如,使用Dagger,您可以为每个图层创建单独的component,这样您就可以编写如下代码:

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) {
     // ...
   }
}

除了上述内容之外,您还可以使用依赖性分析/依赖性分析测试或提交挂钩来自动检测依赖性规则违规(并根据它们触发错误/拒绝提交)。例如,穷人的解决方案是简单地扫描每个文件的包声明及其import语句,然后使用一些启发式方法来检测错误的依赖关系。

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

除自动化方法外,手动方法也有其价值。手动方法包括在代码审查和审核期间执行的常规代码审查和政策。

简而言之,没有一个正确的答案。根据这种分离的重要程度,有必要结合使用几种不同的方法。

答案 1 :(得分:2)

这不是单独使用访问修饰符可以实现的目的。

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

那你还能做什么呢?

  • 您可以尝试实施运行时限制,以防止错误的图层访问工厂对象。但这些限制很容易被故意或偶然地破坏。

  • 您可以使用某种内部"功能"或"凭证"机制,但很难看出你如何防止凭证泄漏。 (如果凭据由安全管理员(见下文)管理,可能有效,但这会使问题更加复杂。)

我认为你能做到的唯一方法是实现自定义SecurityManager,并在每次有可能的层交叉调用时实施安全检查。例如,安全管理器检查调用堆栈以查找调用它的方法/类/包是可能的(尽管很昂贵)。您还需要关闭某些可用于(通常)破坏安全管理器的反射操作。基本上,除了内圈之外的所有内容都需要被视为不受信任的"代码。

坦率地说,使用带有" hacker-proof"的JVM来实现这种功能。安全可能超出了凡人的能力。 (Sun / Oracle还没有成功......)

其他选择是:

  • 依靠程序员纪律。

  • 依靠对代码库的静态分析;例如由记录访问规则的注释辅助。您需要编写自己的代码分析器才能执行此操作。

  • 在图层之间使用地址空间分离和占地面积小,具有安全意义的API。 (我们不再在这里讨论单个传统的JVM ......)