【问题标题】:Is there a way to get maven and eclipse to generate identical class files有没有办法让 maven 和 eclipse 生成相同的类文件
【发布时间】:2016-04-21 14:43:00
【问题描述】:

我有一个使用 maven 的 java 项目。我还使用了 M2Eclipse 插件,所以我可以在项目中使用 eclipse。我还使用 JRebel,以便类更改自动反映在正在运行的服务器中。

问题是我有时在 maven 中编译我的项目,有时在 eclipse 中编译它(更准确地说,每当我保存 java 文件时,eclipse 都会自动编译类文件)。 eclipse 和 maven 编译器最终会为相同的 java 源文件生成不同的类文件,因此 JRebel 经常不必要地重新加载类。有时数百个类文件会被重新加载,即使它们的代码实际上并没有改变。它只是被一个系统或另一个系统重新编译过。

比如这个空类:

public class Stack {

}

使用 maven 编译时,会产生以下结构:

$ javap -verbose Stack.class 
Classfile /tmp/Stack.class
  Last modified Apr 21, 2016; size 240 bytes
  MD5 checksum faf24015026a9cc09caa2c7388930d9a
  Compiled from "Stack.java"
public class Stack
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#13         // java/lang/Object."<init>":()V
   #2 = Class              #14            // Stack
   #3 = Class              #15            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               LStack;
  #11 = Utf8               SourceFile
  #12 = Utf8               Stack.java
  #13 = NameAndType        #4:#5          // "<init>":()V
  #14 = Utf8               Stack
  #15 = Utf8               java/lang/Object
{
  public Stack();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LStack;
}
SourceFile: "Stack.java"

当用 eclipse 编译时,会产生:

$ javap -verbose Stack.class 
Classfile /tmp/Stack.class
  Last modified Apr 21, 2016; size 240 bytes
  MD5 checksum 0d578ab592aebbb947fa85de391019e5
  Compiled from "Stack.java"
public class Stack
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // Stack
   #2 = Utf8               Stack
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LStack;
  #14 = Utf8               SourceFile
  #15 = Utf8               Stack.java
{
  public Stack();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 2: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LStack;
}
SourceFile: "Stack.java"

有没有办法让这两个系统从同一个源文件编译成同一个类文件,这样 JRebel 就不会不必要地重新加载类?

编辑可能的重复:

我不认为这是 this question 的完全相同的副本。那个问题是,出于调试原因,使用 maven 的 ecj 编译器是否是正确的方法?如何配置它以使用配置文件;甚至可以做到。我的问题是如何让 JRebel 不重新加载类,因为它们在没有代码更改时被 javac/ecj 重新编译。

我的问题的解决方案最终可能与其他问题的答案相似(例如:配置 maven 以使用 ecj),或者它可能不同(例如,将 eclipse 配置为使用 javac;或完全其他)。

【问题讨论】:

  • 我猜问题是eclipse没有使用javac;就像 Maven 一样。我以不同的方式“解决”了这个问题......我只有一个为 JRebel 启用的“虚拟”项目......我在文件系统中使用软链接,并且只将那些 java 源文件添加到我想要的虚拟项目中JRebel 上传。
  • This question 谈论在 maven 中使用 Eclipse ecj 编译器。
  • @greg-449 我认为已解决的问题/答案解决了它!我刚刚尝试使用 maven 进行编译,它生成了与 eclipse 生成的类文件相同的类文件。有什么方法可以将您的评论转换为答案,以便我接受?
  • 我的评论不能真正成为答案,因为它是“仅链接”
  • @E-Riz 你能解决我关于为什么这个问题不一定是重复的编辑。

标签: java eclipse maven jrebel


【解决方案1】:

直接回答这个问题:不,javac 和 ecj 是不同的编译器,因此不会产生相同的输出。他们当然会产生兼容的输出,除非有错误。但是这个问题不是关于兼容性的,它实际上是一个关于如何使用不同的构建触发器和 JRebel 的问题。我不了解 JRebel,所以我无法建议如何让它在这种情况下发挥得更好。

正如@gregg-449 所建议的,一种解决方法是将 Maven 配置为使用 ecj,如this answer 中所述。

【讨论】:

    【解决方案2】:

    这不仅仅是它们不同的事实;问题是当你在 Eclipse 中编辑类文件时,类文件将被保存、编译,然后重新加载(这毕竟是它的重点)。所以即使类文件的内容在语义上没有改变,它仍然会被重新加载。

    【讨论】:

    • 但我想重点是:您希望上传您保存的文件。你可以容忍一个文件。他的观点是,当您第一次启用 JRebel 时,它会很好地上传 all 它发现不同的文件。如果 99% 的文件在“语义上”是相同的;很痛。
    • 是的,如果重新加载一个文件,那很好,但如果同时重新加载数百个文件,它将:使服务器陷入爬行状态,最终比重新启动服务器要慢(什么jrebel 是为了防止),并且 b:通常无论如何都不起作用,因为一次重新加载那么多代码时会出现并发症。只要相同的源文件生成相同的类文件,我应该很好,因为我可以使用rebel.check_class_hash=true 设置来避免重新加载相同的类文件,即使它们重新生成。
    猜你喜欢
    • 2015-03-18
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 2015-02-17
    • 2011-11-05
    • 2021-07-24
    • 2010-10-01
    相关资源
    最近更新 更多