29

即使我只更改了一个类,Maven 也会重新编译所有类。我使用这个插件配置:

<plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.1</version>
      <configuration>
        <staleMillis>1</slateMillis>
        <useIncrementalCompilation>true</useIncrementalCompilation>
      </configuration>
    </plugin>
</plugins>

这发生在mvn compile,mvn packagemvn install上。

当然,如果您有 10-15 个文件,这不是问题。但是,我有一千多个源文件,这需要很多时间。

Maven 编译器插件是否有一些隐藏设置来仅重新编译修改过的文件?有什么解决方法吗?

4

2 回答 2

52

概括

虽然你可以告诉 Maven“只重新编译修改过的文件”,但这样做会导致错误的结果。默认行为不是错误,而是有意的设计决定。


useIncrementalCompilation真正做什么

委婉地说,关于这个主题的文档不是最佳的。这是真正发生的事情(基于3.3的AbstractCompilerMojo 源代码) :maven-compiler-plugin

  • useIncrementalCompilation设置为false不推荐
    • 这只会编译比其相应类文件更新的源文件,即自上次编译过程以来已更改的源文件。正如@Ivan 在对另一个答案的评论中指出的那样,这不会重新编译使用更改后的类的其他类,可能会使它们引用不再存在的方法,从而导致运行时出错。
  • useIncrementalCompilation设置为true默认
    • 为了处理上述问题,在这种模式下,编译器插件将确定是否
      • 当前模块所依赖的任何 JAR 文件在当前构建运行中都已更改,或者
      • 自上次编译以来添加、删除或更改的任何源文件。
    • 如果是这种情况,编译器插件会故意重新编译所有源,打印Changes detected - recompiling the module!

所以总而言之,useIncrementalCompilation应该始终保持默认的true.


为什么它不做其他事情

可以理解,有人可能会问:为什么插件不能确定哪些类会受到更改的影响,而只重新编译那些类?在MCOMPILER-205的评论中,Maven 开发者 Robert Scholte 给出了一个简短的理由,后来确认了以下详细解释:

如果任何源文件已更改或删除,则所有文件都将被删除并重新编译。原因是使用默认的 java 编译器简单地重新编译所有内容非常快,可能比替代方法快得多,看起来类似于:

  1. 检测所有更改的文件
  2. 分析所有源文件以映射类之间的所有关系
  3. 计算所有受影响的文件
  4. 重新编译受影响的文件

然而,正如 Robert所写的那样,如果项目使用 Eclipse 编译器,则可能不需要重新编译所有内容,该编译器会执行此分析。但是对于今天的 Maven 用户来说,这是一个有争议的问题,因为它还maven-compiler-plugin没有根据编译器的选择来改变它的行为。

于 2018-04-06T21:02:41.287 回答
37

https://issues.apache.org/jira/browse/MCOMPILER-209

与保加利亚符号一起使用(是 <-> 否)

<useIncrementalCompilation>false</useIncrementalCompilation>表示正确,反之亦然

于 2013-10-29T08:31:01.960 回答