2019-01-10 12:51

@JFinal 顺便分享下心得为后面的同学铺路,关于 IDEA 的到底进行的是make、compile 、还是build。
1、IDEA 默认是没有提供像 Eclipse 的实时自动编译功能,但是可以通过ctrl+shift+A进入Registry修改配置实现,compiler.automake.allow.when.app.running配置的官方配置说明是:Allow auto-make to start even if developed application is currently running. Note that automatically started make may eventually delete some classes that are required by the application,意思是说:允许在应用运行时开启auto-make功能,但是最终可能会删除一些应用需要的class文件。
2、通过观察每次修改文件触发 IDEA 自动编译,检测target目录中所有class文件状态,可见只有对应修改后的class文件状态发生了变化。
3、通过捕获 IDEA 自动编译时期文件系统的所有状态事件,只有对应修改的class。

综上我的结论是: IDEA 的模式应该还是属于make,只有在java文件变化了才会触发,而且也只针对变化的文件而并非全项目build。但是比较奇葩的是,它不是直接修改对应class文件,而且先删除再创建再修改。( 以上分析基于 IDEA 2018.2.6版本 )

2019-01-10 12:27

@JFinal 可行,我这边项目先采用这种方式

2019-01-10 12:26

@JFinal 好的,我这边开发暂时这样使用,期待你那边的更新

2019-01-10 10:58

@JFinal 通过研究IntelliJ IDEA的自动编译机制找到问题了根源了:
并非所有IDE 的自动编译功能都是直接对class文件进行修改操作,例如 IntelliJ IDEA 就会针对变化的class文件先进行删除操作,再创建新的class文件,然后对新创建的class文件进行修改操作,因此会产生一系列系统文件变化事件,如下:
1、class文件修改事件
2、class文件删除事件
3、class文件所在目录修改事件
4、class文件创建事件
5、class文件修改事件(真正写入class文件内容)
6、class文件所在目录修改事件

为了兼容这类IDE,不在监听到class文件修改事件后便立即进行热加载过程,因为有些修改事件实际上是无效事件,比如上述事件1,虽然是class文件修改事件,但是立马又产生了class文件删除事件将class文件删除了,此时触发热加载,将会引起class文件不存在异常。
因此当捕获到class文件修改事件后,不立即进行热加载,而是继续观察数毫秒,判断是否还有后续删除事件,如果有则视为此次修改事件等同于删除事件不进行热加载;如果没有才认为是真实修改行为,此时才进行热加载操作。

此前通过对HotSwapClassLoader类的改造方式比较丑陋粗暴,而且会影响性能,现通过分析清楚问题根源后从监控事件入手,在原因监听操作基础上只增加了一步真实修改行为分析操作,在不影响性能的情况下实现了对怪异IDE行为的兼容。经测试IntelliJ IDEA、Eclipse下目前都正常。

2019-01-09 11:35

@JFinal 这个我之前也考虑过,但是通过观察文件系统时间判断,IDE只是针对修改后的文件重新生成的class

2019-01-09 11:25

@JFinal 确实针对其他正常加载不到的情况会影响性能,我再考虑下,同时我也在研究IntelliJ IDEA的automake机制,看为什么我这边会出现

2019-01-09 11:13

@JFinal 我已经在码云上提交pull requests啦

2019-01-09 09:29

@JFinal 猜想可能是IntelliJ IDEA在生成新的class文件后没有立即释放文件资源,导致虽然触发了系统的文件修改事件,但是class文件还不可读,导致HotSwapClassLoader加载不到,稍微延迟数百ms后便可以正确加载。

2019-01-09 09:20

@JFinal 这个我已经配置过了,我遇到的问题跟配置无关,通过看JFinal-undertow源码找到了原因,是因为IntelliJ IDEA在自动生成class文件时候有延时,导致com.jfinal.server.undertow.hotswap.HotSwapClassLoader加载新class文件时抛出未找到异常,我在HotSwapClassLoader 类中加入重试机制,已经解决了这个问题。