Thinking in Java
          Java開發(fā)技巧與實(shí)踐
          posts - 9,comments - 6,trackbacks - 0

          一、問題

          當(dāng)開啟 minimizeJar 后,精簡(jiǎn)的Jar運(yùn)行會(huì)出現(xiàn)如下錯(cuò)誤:

          The image could not be loaded: FileImageDescriptor(location=class org.eclipse.jface.dialogs.TitleAreaDialog, name=images/title_banner.png)
          org.eclipse.jface.resource.DeviceResourceException: Unable to create resource FileImageDescriptor(location=class org.eclipse.jface.dialogs.TitleAreaDialog, name=images/title_banner.png)
                  at org.eclipse.jface.resource.ImageDescriptor.createResource(ImageDescriptor.java:184)
                  at org.eclipse.jface.resource.DeviceResourceManager.allocate(DeviceResourceManager.java:55)
                  at org.eclipse.jface.resource.AbstractResourceManager.create(AbstractResourceManager.java:88)
                  at org.eclipse.jface.resource.ResourceManager.createImageWithDefault(ResourceManager.java:195)
          …………

          出現(xiàn)這個(gè)錯(cuò)誤的直接現(xiàn)象是所有的圖片——包括圖標(biāo)——都無法正確顯示。

          二、分析

          開始以為是resources打包錯(cuò)誤導(dǎo)致沒有被壓進(jìn)jar包,不過分析jar包內(nèi)容發(fā)現(xiàn)并沒有文件缺失,然后開始分析minimizeJar的機(jī)制。文檔上說:

          <minimizeJar>
          When true, dependencies will be stripped down on the class level to only the transitive hull required for the artifact. Note: Usage of this feature requires Java 1.5 or higher.

          由此來看,shade做的只是做了靜態(tài)調(diào)用分析,并沒有做動(dòng)態(tài)類加載運(yùn)行分析,因此極大可能問題是出在這里了。而且從拋出的異常來看,有可能是圖片文件格式無法解析導(dǎo)致了圖片資源創(chuàng)建失敗。

          那么之后的調(diào)試方法就簡(jiǎn)單了,首先上verbose大法,直接加verbose:class參數(shù),分別運(yùn)行正常的和異常的Jar包,從輸出信息發(fā)現(xiàn)了端倪:

          [Loaded java.lang.IndexOutOfBoundsException from C:\Program Files\Java\jre1.8.0_151\lib\rt.jar]
          [Loaded java.lang.ArrayIndexOutOfBoundsException from C:\Program Files\Java\jre1.8.0_151\lib\rt.jar]
          [Loaded org.eclipse.swt.internal.image.WinBMPFileFormat from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.GIFFileFormat from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.WinICOFileFormat from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.JPEGFileFormat from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.JPEGSegment from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.JPEGFixedSizeSegment from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.JPEGStartOfImage from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PNGFileFormat from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngInputStream from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngDecodingDataStream from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngChunkReader from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngIhdrChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngFileReadState from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngPlteChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngIdatChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngIendChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.image.PngTrnsChunk from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.win32.BITMAPINFOHEADER from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.jface.window.ToolTip$ToolTipOwnerControlListener from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.jface.window.ToolTip$$Lambda$19/1873653341 from org.eclipse.jface.window.ToolTip]
          [Loaded org.cncert.xac.utils.ResourceManager from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.widgets.ToolItem from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.internal.win32.TBBUTTON from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.jface.resource.AbstractResourceManager$RefCount from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.layout.FormData from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.swt.layout.FormAttachment from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.jface.dialogs.TitleAreaDialog$1 from file:/E:/Temp/*****.jar]
          [Loaded org.eclipse.jface.window.ToolTip$TooltipHideListener from file:/E:/Temp/*****.jar]

          注意上方紅色的字體,在異常的Jar包輸出中是沒有的,同時(shí)檢查了Jar包中果然沒有打包這幾個(gè)類!將這幾個(gè)類手動(dòng)加入Jar包后,異常的Jar包可以正常運(yùn)行了。

          從源代碼看,這幾個(gè)類型是SWT在運(yùn)行時(shí)動(dòng)態(tài)加載的,由 org.eclipse.swt.internal.image.FileFormat 動(dòng)態(tài)加載,相關(guān)代碼如下:

          package org.eclipse.swt.internal.image;


          import java.io.*;

          import org.eclipse.swt.*;
          import org.eclipse.swt.graphics.*;

          /**
           * Abstract factory class for loading/unloading images from files or streams
           * in various image file formats.
           *
           
          */
          public abstract class FileFormat {
              static final String FORMAT_PACKAGE = "org.eclipse.swt.internal.image"; //$NON-NLS-1$
              static final String FORMAT_SUFFIX = "FileFormat"; //$NON-NLS-1$
              static final String[] FORMATS = {"WinBMP", "WinBMP", "GIF", "WinICO", "JPEG", "PNG", "TIFF", "OS2BMP"}; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ //$NON-NLS-6$//$NON-NLS-7$//$NON-NLS-8$

              LEDataInputStream inputStream;
              LEDataOutputStream outputStream;
              ImageLoader loader;
              int compression;

          static FileFormat getFileFormat (LEDataInputStream stream, String format) throws Exception {
              Class<?> clazz = Class.forName(FORMAT_PACKAGE + '.' + format + FORMAT_SUFFIX);
              FileFormat fileFormat = (FileFormat) clazz.getDeclaredConstructor().newInstance();
              if (fileFormat.isFileFormat(stream)) return fileFormat;
              return null;
          }

          三、Maven配置的修改

          在官方文檔中,可以使用filter來顯式包含不想被minimizeJar優(yōu)化掉的內(nèi)容,但是目前filter還無法做到針對(duì)一個(gè)artifact中選擇性對(duì)某個(gè)目錄下的文件不做優(yōu)化。
          例如,我希望shade不對(duì)org/eclipse/swt/internal/image/**做優(yōu)化,我的配置是這樣的:

          <filter>
               <artifact>org.eclipse:swt.win32.x86_64</artifact>
               <includes>
                    <include>org/eclipse/swt/internal/image/**</include>
               </includes>
          </filter>

          但最終的結(jié)果是只打包了這個(gè)目錄內(nèi)的類,而這個(gè)artifact中的其他類全部被removed,因?yàn)?a >官方demo中有這樣一句話:

          As of version 1.6, minimizeJar will respect classes that were specifically marked for inclusion in a filter. Note that specifying an include filter for classes in an artifact implicitly excludes all non-specified classes in that artifact.

          所以我只能讓shade將swt的artifact全部保留,不做優(yōu)化。

          <filter>
                 <artifact>org.eclipse:swt.win32.x86_64</artifact>
                 <includes>
                          <include>**</include>
                 </includes>
          </filter>

          或者使用artifactSet達(dá)到同樣的效果。

          四、總結(jié)

          1. 目前shade的機(jī)制是靜態(tài)分析,所以可能會(huì)優(yōu)化掉很多動(dòng)態(tài)加載的類,對(duì)于使用動(dòng)態(tài)加載較多的工程,在發(fā)布時(shí)需要特別注意。
          2. 目前shade的配置無法在一個(gè)artifact內(nèi)顯式指定某個(gè)路徑不優(yōu)化(或許有,但我確實(shí)沒找到,歡迎知道的朋友留言告知),只能顯式保留整個(gè)artifact不做優(yōu)化。


          無人分享的快樂不是真快樂,沒人分擔(dān)的痛苦是真痛苦。
          posted on 2019-04-29 16:33 Feenn 閱讀(796) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 七台河市| 枣庄市| 武川县| 饶阳县| 抚州市| 北票市| 仁布县| 芦山县| 泰兴市| 隆昌县| 新河县| 红安县| 华坪县| 许昌市| 瓮安县| 乌什县| 锡林郭勒盟| 大庆市| 夏河县| 黑河市| 双城市| 宁海县| 长汀县| 宁城县| 水城县| 东莞市| 高要市| 宁海县| 鄂温| 措美县| 安义县| 黄骅市| 新化县| 宁海县| 泾源县| 浦县| 晋宁县| 都兰县| 武乡县| 临沭县| 钟山县|