1. 离线安装的整体思路与方案选型
1.1 为什么非要离线安装
很多开发者在拿到一台新电脑、或者被分配到内网开发环境之后,第一件事就是往Eclipse里装插件。按正常流程,Help -> Install New Software,填一个在线更新地址,等着列表加载出来,勾选、下一步,很顺畅。但这个流程在真实的开发环境里经常卡住,我遇到过的情况大致有三类。
第一类是机器根本不在外网,或者只有一部分机器能上网。这种情况在国企、银行、军工这类网络隔离环境里很常见。开发机连外网是违规的,只能通过U盘拷包、或者走内部软件仓库来装东西。别说Freemarker IDE插件,就连Eclipse本体都得离线分发。
第二类是外网访问慢。更新站点在国外,或者本身就不稳定,加载插件列表经常卡在某个百分比,下载到一半就报网络错误,重试以后又从零开始,让人非常烦躁。实测下来,有些站点哪怕开了代理,下载jar包的速度也只有几十KB,一个几兆的插件要等十来分钟,这种体验肯定顶不住。
第三类是版本兼容问题。在线安装会拿到站点上最新版插件,但最新版不一定适配你当前的Eclipse版本。比如Eclipse 2019-06装到最新版的某个插件,可能因为API不兼容直接装不上。离线包的形式反而能锁定你验证过的版本,团队内部统一分发,谁装的结果都一样。
所以离线安装不是一个可有可无的小技巧,而是内网开发环境、受限网络环境下的刚需能力。下面整个方案就是围绕“在一台能上网的机器上准备离线包,在目标机器上用手动方式安装”来展开的。
1.2 两条主流离线安装路线
Eclipse装插件,离线场景下基本就两条路:
一条是Help -> Install New Software,点Add按钮,把更新站点的Archive文件路径填进去,走图形化界面安装。用到的Archive文件本质上就是把一个更新站点里的内容(features目录 + plugins目录 + site.xml)打成一个zip包,Eclipse会把这个zip当成一个本地更新站点来读取。
另一条是把插件直接丢到Eclipse安装目录的dropins文件夹里。Eclipse在启动时会扫描dropins目录,把里面按约定结构放置的插件组件加载进来。这种方式的优点是操作最简单,拷贝文件就够了,不经过安装向导。缺点是有时候需要重启加-clean参数才能识别,而且插件之间如果有依赖关系,光靠dropins不好处理。
我的建议是:能用Install New Software走Archive就优先用这条路,安装过程透明、能选组件、能看依赖冲突提示,出问题好排查。dropins适合分发那种结构简单的单体插件,或者你手头只有一个jar包、没有现成站点打包文件的情况。后面两个插件的安装我分别用到了这两种方式,正好把两条路都讲清楚。
2. 安装前的准备工作:工具包与版本判断
2.1 Freemarker IDE离线包获取途径
Freemarker IDE是Eclipse下写FreeMarker模板的必备插件,提供语法高亮、标签补全、模板校验、表达式错误提示这些功能。没有它,在Eclipse里打开ftl文件就是纯文本,颜色灰扑扑一片,写错指令也没人提醒,效率低得没眼看。
获取离线安装包比较实用的办法是在一台能上网的机器上,把第三方更新站点整个拉下来打包。以Freemarker IDE的常用更新地址为例,直接用Eclipse访问更新站点后,它会在当前工作区目录下的p2/org.eclipse.equinox.p2.engine目录里缓存一堆下载好的jar包。理论上可以从缓存里翻出来,但路径太深、文件命名是版本号加随机串,整理起来不直观,我试过一次就放弃了。
更推荐的方法是用Eclipse的“Export Bundles”或者直接手动把站点内容打包。操作方式也不复杂:在有网的机器上打开Eclipse,用Install New Software先在线安装一遍Freemarker IDE,安装成功后,在Eclipse安装目录下的features和plugins目录里找到相关的jar包。Freemarker IDE插件的feature包命名一般是类似org.jboss.tools.freemarker.feature这种,plugins目录下是一堆org.jboss.tools.freemarker_*.jar开头的包。把对应的feature和plugin挑出来,按下面这个目录结构放好:
freemarker-offline/ ├── features/ │ └── org.jboss.tools.freemarker.feature_版本号.jar └── plugins/ ├── org.jboss.tools.freemarker_版本号.jar └── com.jboss....(依赖包).jar然后整体压缩成zip,这就是一个可以分发的Archive。注意依赖包要一并打包,Freemarker IDE通常会依赖一些公共基础库,漏了依赖的话安装时会报缺少requirement的错误。多装几遍之后,我习惯把依赖jar也从plugins目录里一起挑出来,怎么判断哪些是依赖呢?看插件列表里org.jboss.tools开头的、以及com.thoughtworks.xstream这类第三方库,基本就是。
如果你内网机完全无法连接外网,那就需要一台有网的机器来制作这个离线包,然后通过U盘拷贝到内网。实际操作中,U盘拷贝还需要注意文件完整性,zip包大一点就容易拷半截,建议拷完看一眼文件大小对不对,或者直接算一下MD5再传。
2.2 Jad反编译插件的完整配件
Jad反编译插件这个话题要比Freemarker IDE复杂一点,因为它实际上是两部分组成的:Eclipse的插件外壳JADClipse,加上真正的反编译引擎jad可执行文件。
JADClipse只是负责集成,它给Eclipse增加了双击class文件时用jad反编译查看源码的功能,并提供Source Attachment的关联方式。真正干活的是jad.exe这个命令行工具,JADClipse在运行时通过调用jad.exe来把class字节码转成java源码展示出来。
所以准备材料的时候要拿两样东西:
第一样是JADClipse的插件包。常见的是net.sf.jadclipse_版本号.jar,从sourceforge或者GitHub上可以找到。注意这个包是放到Eclipse的dropins目录下的,不需要走Install New Software。
第二样是jad.exe可执行文件。搜索“jad”加版本号就能找到对应的压缩包,解压后里面是一个jad.exe,或者Linux和Mac对应的是jad二进制文件。把这个可执行文件存到一个固定的本地路径,比如D:\tools\jad\jad.exe,配置JADClipse时用得到。
这里有一个历史遗留问题需要提醒:JADClipse很久没有更新了,它适配的是老版本的Eclipse。如果你用的是新版Eclipse(比如2020年以后的4.20+版本),直接放dropins可能不生效,需要后面说到的小技巧来处理。另外jad本身支持的字节码版本也有限,它针对的是JDK 1.4以前的class格式,太新的Java版本(比如Java 8以上编译出来的大部分class)反编译时会直接报错,这些都是踩坑高发区,到后面排查部分再展开。
2.3 版本兼容性判断的几个要点
离线安装最怕就是装完重启,一看报错对话框,一堆 “cannot resolve plug-in” 或者 “requires bundle” 的提示。这些基本都和版本匹配有关。判断版本兼容性,我自己总结了一套顺手的方法:
第一,看Eclipse版本。Freemarker IDE插件对老版本Eclipse支持得比较好,如果你用的是Eclipse Kepler、Luna、Mars这些老版本,相关版本的Freemarker IDE都比较稳。新版Eclipse建议找对应新一点的插件版本,但也要注意新版插件有时候需要高版本JDK来运行,低版本JDK环境跑Eclipse会出现加载失败。
第二,看JDK版本。Eclipse本身用什么JRE启动,和你装的插件的class编译级别也有关系。比如某些插件是Java 8编译的,你用Java 7启动Eclipse,插件就会出现NoClassDefFoundError。遇到这类问题别急着怀疑Eclipse本身,先确认一下启动Eclipse的JDK版本和插件的class版本兼容。
第三,看插件间的依赖。freemarker ide插件在安装时往往会同时要求安装一些公共组件,如果你只打包了它本身的jar而漏掉了依赖,安装时就会看到类似错误。jadclipse相对独立,但也需要它依赖的某些老版本Eclipse基础插件。
3. 动手实操:Freemarker IDE插件的离线安装
3.1 方法一:Install New Software加载本地Archive
这是我最推荐的路线,过程透明、出错可见。把前面打包好的zip文件复制到目标机器本地,假设路径是D:\install\freemarker-offline.zip。
打开Eclipse,菜单Help -> Install New Software,点击Add按钮:
- Name填一个自定义名字,比如“Freemarker IDE Offline”,随便取,只是显示用。
- Location选“Archive”,点击右侧的Local按钮浏览到D:\install\freemarker-offline.zip。
确认后,中间的列表区域会列出从zip解析出来的插件条目,也就是你打包的feature。把复选框勾上,一路Next让Eclipse计算依赖。如果依赖有问题,会在这一步弹出来告诉你缺少什么。没问题的话就能看到安装详情和许可协议,点击Finish开始装。
装的过程会有一个进度条,走完后提示重启Eclipse。重启之后Freemarker IDE就生效了。
提示:如果列表里什么都出不来,先确认zip内部是不是标准site结构。有些包解压后是多了一层目录层级,Eclipse读取不到。标准结构是features和plugins文件夹直接在zip根目录下,嵌套一层目录都不行。遇到这种情况重新打包就好。
3.2 方法二:dropins目录直接投放
dropins方式适合你没有zip包、只有插件jar和依赖jar的场景。找到Eclipse安装目录下的dropins文件夹,如果不存在就新建一个。在dropins下按插件名建个子目录,比如:
dropins/ └── freemarker/ ├── features/ │ └── org.jboss.tools.freemarker.feature_版本号.jar └── plugins/ └── org.jboss.tools.freemarker_版本号.jarEclipse启动时会把dropins下所有子目录里符合结构的内容都扫描加载。这个方法比分发的zip灵活,因为你不需要把整个站点压缩再解压,直接按目录结构放就行。
但要注意dropins加载的坑:一是要彻底重启Eclipse,最好是带-clean参数启动,让它重新扫描插件缓存;二是如果Eclipse没有从dropins加载到,同时安装目录下的plugins文件夹里也找不到这个jar,那就说明扫描没成功或有缓存残留。遇到这种情况,用命令行启动Eclipse并在启动参数里加上-clean,就能强制清掉缓存重新扫描。
3.3 安装完成后的功能验证
Freemarker IDE装好之后,最简单的验证方式是在Eclipse里新建一个后缀名为ftl的文件。新建文件时在向导的搜索框里输入“freemarker”或者“ftl”,如果能看到对应的模板文件模板,说明插件已经注册成功。打开ftl文件,默认编辑器如果是Freemarker Editor,并且代码有像Java语法高亮那样的颜色区分,就说明正式生效了。
另外还要看一下Window -> Preferences里是否多出一个Freemarker相关的配置项。我在实践中常见的Freemarker配置项包括Template Data、Validation等,在这里可以设置模板include路径和默认编码。如果你经常做国际站项目,建议把编码默认成UTF-8,防止ftl文件的中文乱码。
全套验证过了,再进阶到使用层面。Freemarker Editor里输入<#if>这类指令标签,会弹出代码提示;编辑后保存,如果有语法错误,编辑器会自动标红。这一整套体验对模板开发的帮助很大,在没有格式化代码的编辑器里写ftl简直是折磨。
4. Jad反编译插件的离线安装与配置
4.1 JADClipse插件投放与激活
JADClipse插件本体实际上是一个单一的jar包,我通常在检查完Eclipse版本确认兼容后,直接把net.sf.jadclipse_版本号.jar放到了Eclipse安装目录的dropins\jadclipse文件夹下(也自己建了plugins子目录)。为了保险,我是把jar放到了plugins子目录里。
放完后同样是重启Eclipse,加-clean参数清一次缓存。启动后到Window -> Preferences里看是否出现“JadClipse”配置节点,如果有,说明插件外壳加载成功了。
有一个非常常见的问题:在新版Eclipse(2020年以后版本)里,JADClipse可能不显示在Preferences中,或者显示后双击class文件时没有反应。原因一般是新版Eclipse变卖了老的class file viewer机制,JADClipse这种依赖老API的插件直接失效。这时候的解决方案有一个,就是在Eclipse的plugins目录里塞一个老版本的org.eclipse.jdt.ui插件,覆盖掉新版里面的对应组件,靠这种“插件降级”的方式强行给JADClipse续命。具体做法是找到老Eclipse版本中对应的jar(我一般用4.2版本的),放到plugins目录后加-clean重启。这个方法可以不保证对所有新版Eclipse都管用,但实测对4.20到4.25这一带Eclipse有较高成功率。
注意:插件降级属于高风险操作,可能会改掉Eclipse JDT相关的行为,影响原有Java开发体验。操作前务必先备份原jar文件,后续如果遇到别的异常,能随时恢复。
4.2 指定jad可执行文件路径
插件激活后,下一步是配置可执行文件路径。在Window -> Preferences -> JadClipse里,找到Path to decompiler这一项,浏览选择或者直接填写jad.exe的完整路径,比如D:\tools\jad\jad.exe。
这里还有几个参数值得说明,我实际操作时会保持默认大体不变,但会改两个地方:
一是Misc目录里的“Use first class parameter name”之类选项,这影响反编译出来的参数名是否还原成原定义的名称。jad反编译时如果没有调试符号,参数名通常显示为i、j这种占位符,开启了某些选项也不会改变现状,所以期望值别太高。
二是Directory for temporary files,建议指定到一个正常的临时目录,别放到中文路径下,jad老版本对非英文字符路径支持很差,放到中文目录会出现无法创建临时文件的反编译失败。
配置完成后点击OK,然后随便找一个编译好的class文件,右键打开方式选择“JadClipse”或者直接双击关联的class文件,就能看到反编译出来的Java源码了。如果在Package Explorer中选中class文件,右键选择“Open With” -> “JadClipse”,效果也一样。
4.3 反编译的两种使用姿势
JADClipse的具体使用场景,其实不止查看单个class文件那么简单。我自己在排查线上问题时,最常用的两种姿势:
第一种是直接看class文件源码。在项目依赖里找到某个第三方jar包,用压缩软件打开jar,找到里边一个class文件,可以通过Eclipse的反编译插件来查看实现的源码。注意这个场景要与JadClipse关联Source attachment配合,否则打开的可能是空内容。
第二种是用反编译出的源码作为调试辅助。当你在Eclipse里单步调试进了一个没有源码的第三方class时,会看到一片空行。有了反编译插件,工具会直接把jad的还原结果填充进去,至少能看到代码走到哪一步、做了什么操作,对排查问题很有帮助。
不过要明白反编译出来的代码不是原始源码的逐字恢复,函数名、注释、局部变量名都有很大失真。打开jar并查看class功能的体验,还是以理解整体逻辑为主,别太抠细节。
5. 离线安装的常见问题与排查经验
5.1 插件装了但完全不生效
现象是插件安装过程没有报错,重启后却找不到任何插件的入口。排查思路从以下几个方向看:
首先确认安装方式对应的目录是否正确。Install New Software方式安装的插件会散布到Eclipse的features和plugins目录,如果你安装完发现这两个目录里没有新增的jar,说明安装过程其实没有成功复制文件。dropins方式则要检查目录结构层级,Eclipse扫描dropins的深度有限,目录嵌套太深会扫描不到。
其次是启动参数。特别是dropins方式,强烈建议第一次启动时加-clean参数。不加-clean的情况下,Eclipse会用缓存目录里的插件清单启动,新投放进去的jar可能不会被注册。命令行参数是eclipse.exe -clean,Mac系统是./Eclipse.app/Contents/MacOS/eclipse -clean。
再次是确认Eclipse启动时用的JDK版本。低版本JDK运行高版本编译的插件会产生LinkageError,Eclipse会把这个插件标记为“已安装但未启动”,但界面上并不明显。我在内网机器上就遇到过好几回,JDK是1.6配Eclipse 4.x,装了新插件以后死活不出来,换成1.8启动就正常了。
5.2 jad反编译高版本class文件报错
这种报错的根源是字节码版本超出了jad支持的解析范围。jad最新版的发布日期非常早,对Java 8以后引入的字节码新特性基本不认识,遇到这类class通常直接抛异常,如“itself”或干脆产出一个空文件。
解决思路有几条,按推荐程度排序:
第一,换用支持新版字节码的反编译工具。Eclipse现在自带fernflower反编译器(在JDT里),打开Preferences -> Java -> Decompiler就能看到。fernflower对Java 8以后的class支持要完善得多,你完全可以把fernflower与JADClipse同时保留,各用各的场景。虽然题目说装jad,但实际操作经验是碰到高版本class就切fernflower,保留jad处理老版本包即可。
第二,如果一定要用jad,可以在项目构建时降级编译的目标版本。比如用javac -source 1.4 -target 1.4重新编译一次相关源码,生成的class就能被jad解析。但这只适用于有源码且能稍降版本编译的情况,对第三方jar无效,所以实用性有限。
第三,处理老版本jar包时,jad依然有它的优势:工具体积小、反编译出的代码简洁度好。所以在访问老项目、系统源码级别的class时,我仍然会配置并保留用它。
5.3 离线包分发时的其他隐藏坑
在实际分发离线包的经验里,还遇到过几个与网络下载本身相关的问题:
一是从网络站点打包时,zip损坏或缺文件。下载的zip在解压阶段直接报文件损坏,几乎都是网络传输导致的。解决办法是下载后用压缩软件测试一下能不能完整解压,不要直接拿去装。生产环境里分发之前,我会习惯先在同一个Eclipse版本上跑一次安装验证,确认没问题再分发。
二是内网机器的Eclipse版本和打包机器不一致。在A机器上正常安装的插件包,放到版本差异较大的B机器上,可能因为缺少某些API而失败。离线包在分发前要看清楚包内含插件所依赖的Eclipse插件版本范围,尽量让两端Eclipse版本保持一致。
三是部分环境U盘传输会加上只读属性,导致Eclipse安装时写不进安装目录。装插件失败时检查一下安装目录是否只读,Windows下如果Eclipse安装在Program Files目录里,还需要管理员权限运行才能写入。这个坑多发生在Windows系统上,解决办法是用管理员身份启动Eclipse再安装,或者把Eclipse挪到非系统盘目录。
四是缓存目录空间不足。安装插件时Eclipse会在工作区的p2目录里创建临时文件,磁盘空间不够时安装会中途失败,且没有明显提示。内网机器经常有C盘爆满的情况,提前清理一下工作区下的.p2目录,通常能解决。
5.4 插件配置项与项目构建联动
Freemarker IDE安装后,还可以做一步额外配置让模板校验和项目构建真正联动起来。在Preferences -> Freemarker -> Validation里,把模板语法校验打开。这样当你保存一个ftl文件时,Eclipse会对标签闭合、表达式写法做静态检查,语法错误会直接显示在Problems视图里。
同样地,在项目属性里可以把ftl文件的关联编码设置成UTF-8,避免和项目其他文件的编码不一致。Maven多模块项目里,公共模板放在一个独立的resources模块下,ftl文件经常出现中文乱码或标签不闭合的问题,设置好编码和校验可以省下很多后续排查的功夫。
Freemarker IDE还支持自定义标签指令的告诉校验。如果你在项目里定义了自定义的@指令,可以在Preferences -> Freemarker -> Templates里注册这些指令,编辑器就不会把它们误报成未知标签。我在此步骤上花过一些时间,调试好之后,模板开发的体验和写Java代码已经非常接近。
6. 顺手整理一份离线插件仓库更方便
如果你们团队不止一个人需要配置这个环境,强烈建议把离线包统一管理,不要每次都在机器之间拷来拷去。我自己习惯在共享目录里建一个“eclipse-offline-plugins”文件夹,按插件名分好子目录,每个子目录里放:
- 插件本身的zip包或者jar集合
- 一份简洁的README文件,记录适配的Eclipse版本、JDK要求、安装步骤和踩过的坑
- 如果涉及jad这类需要在外部配置可执行文件的插件,单独备注好工具存放路径要求
这样后续新同事入职,照着README操作一遍就能搞定环境,不用每次都消耗精力去摸索。把插件包、依赖、配置说明固定下来,整个团队的Eclipse环境质量也能保持在一个水平线上。
有个小细节再提醒一下:离线安装的插件包如果没有特殊原因,尽量保持版本锁定。因为团队项目可能需要稳定环境,你升级了一次插件版本,本地文件模板的高亮和补全可能在某些地方表现不同,同一个库代码多人开发时,工具行为不一致会造成无谓的diff和沟通成本。版本锁定后,就算要升级也是整个团队统一升级。
最后再分享一个小技巧:如果安装Freemarker IDE后,打开ftl文件仍然显示为纯文本编辑器,多半是文件关联没设好。在Window -> Preferences -> General -> Editors -> File Associations里把*.ftl关联到Freemarker Editor即可。这个操作经常被忽略,特此记一笔。