2015年7月9日星期四

Java 编译:概念和实现

java编译的概念

编译 Java 源代码需要用到以下组件:

  • 类路径,编译器从其中解析库类。编译器类路径通常由一个有序的文件系统目录列表和一些归档文件(JAR 或 ZIP 文件)组成,归档文件中包含先前编译过的 .class 文件。类路径由一个 JavaFileManager 实现,后者管理多个源代码和类 JavaFileObject 实例以及传递给JavaFileManager 构造函数的 ClassLoader。JavaFileObject 是一个 FileObject,专门处理以下任一种由编译器使用的JavaFileObject.Kind 枚举类型:

  1. SOURCE
  1. CLASS
  2. HTML
  3. OTHER
   每个源文件提供一个 openInputStream() 方法,可以作为 InputStream访问源代码。
  • javac 选项,以 Iterable<String> 的形式传递

  • 源文件 — 待编译的一个或多个 .java 源文件。JavaFileManager 提供了一个抽象的文件系统,可以将源文件和输出文件的文件名映射到JavaFileObject 实例(其中,文件 表示一个惟一名称和一串字节之间的关联。客户机不需要使用实际的文件系统)。在本文的示例中,JavaFileManager 管理类名与 CharSequence 实例之间的映射,后者包含待编译的 Java 源代码。JavaFileManager.Location包含一个文件名和一个标记,该标记可以表明该位置是源代码还是一个输出位置。 ForwardingJavaFileManager 实现 Chain of Responsibility 模式(参见 参考资料),允许将文件管理器链接在一起,就像类路径和源路径将 JAR 和目录链接起来一样。如果在这条链的第一个元素中没有发现 Java 类,那么将对链中的其他元素进行查找。

  • 输出目录,编译器在其中编写生成的 .class 文件。作为输出类文件的集合,JavaFileManager 也保存表示编译过的 CLASS 文件的JavaFileObject 实例。

  • 编译器。JavaCompiler 创建 JavaCompiler.CompilationTask 对象,后者从 JavaFileManager 中的 JavaFileObject SOURCE对象编译源代码,创建新的输出 JavaFileObject CLASS 文件和 Diagnostic(警告和错误)。静态ToolProvider.getSystemJavaCompiler() 方法返回编译器实例。

  • 编译器警告和错误,这些内容通过 Diagnostic 和 DiagnosticListener 实现。Diagnostic 是编译器发出的警告或编译错误。Diagnostic 指定以下内容:
  1. Kind(ERROR、WARNING、MANDATORY_WARNING、NOTE 或 OTHER)
  2. 源代码中的位置(包括行号和列号)
  3. 消息
   客户机向编译器提供一个 DiagnosticListener,编译器可通过它向客户机发回诊断信息。DiagnosticCollector 是一个简单的DiagnosticListener 实现。

    图 1 展示了 javax.tools 中的 javac 概念与其实现之间的映射:

安全风险和策略


如果应用程序允许用户随意输入 Java 源代码,那么会存在一些内在的安全风险。类似 SQL 注入(参见 参考资料),如果系统允许用户或其他代理提供原始的 Java 源代码来生成代码,那么恶意用户可能会利用这一点。例如,在本文的 Plotter 应用程序中,一个有效的 Java 表达式可能包含匿名的嵌套类,它可以访问系统资源、在受到拒绝服务攻击时产生大量线程或者执行其他行为。这些行为被称为 Java 注入。这种应用程序不应该部署在非信任用户可以随意访问的不可靠位置,例如作为 servlet 或 applet 的 Java EE 服务器。相反,javax.tools 的大多数客户机应该限制用户输入并将用户请求转换为安全的源代码。

使用这种包时可以采用的安全策略包括:
  • 使用定制的 SecurityManager 或 ClassLoader 阻止加载匿名类或其他无法直接控制的类。
  • 使用源代码扫描程序或其他预处理程序,删除含有可疑代码构造的输入。例如,Plotter 可以使用 java.io.StreamTokenizer 并删除含有 {(左侧大括号)字符的输入,从而有效阻止了匿名或嵌套类的声明。
  • 使用 javax.tools API,JavaFileManager 可以删除任何预料之外的 CLASS 文件的写入。例如,当编译某个特定类时,对于要求保存预料之外的类文件的任何调用,JavaFileManager 将抛出一个 SecurityExeception 异常,并只允许生成用户无法猜测或欺骗的包名或类名。Plotter 的 newFunction 方法使用的就是这种策略。
整理自:http://www.ibm.com/developerworks/cn/java/j-jcomp/?S_TACT=105AGX52&S_CMP=tut-cto

1 条评论: