首页 > 解决方案 > 使用 Maven 动态加载类的 Jar 着色

问题描述

在将 jar 上传到 AWS lambda 之前,我正在使用 maven 插件对其进行遮蔽和最小化。但是,由于缺少类,我遇到了运行时异常。据我所知,这是由于一些“动态”类加载或其他原因,但我不确定 A)是否有解决方案或 B)它可能是什么,超出了我已经做出的努力。我阅读了一些关于 jar 着色的好 [articles][1] 并且我想我理解了总体思路,但是我在任何地方都找不到我的特定问题的示例。

[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /home/ro007848/Workspace/geometry-service/target/geometry-service-1.0.0.jar with /home/ro007848/Workspace/geometry-service/target/geometry-service-1.0.0-shaded.jar

下面是我在 cloudwatch 中看到的堆栈跟踪:

Caused by: java.lang.RuntimeException: Unable to find function Length
at org.geotools.filter.FunctionFinder.findFunction(FunctionFinder.java:208)
at org.geotools.filter.FunctionFinder.findFunction(FunctionFinder.java:152)
at org.geotools.filter.FunctionFinder.findFunction(FunctionFinder.java:129)
at org.geotools.filter.FilterFactoryImpl.function(FilterFactoryImpl.java:819)
at org.geotools.feature.FeatureTypes.createLengthRestriction(FeatureTypes.java:148)

这是我的 pom 文件的内容:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <minimizeJar>true</minimizeJar>
                <filters>
                    <filter>....</filter>
                    <filter>
                        <artifact>org.geotools:*</artifact>
                        <includes>
                            <include>**</include>
                        </includes>
                    </filter>
..........
                    <filter>....</filter>
                    <filter>
                        <artifact>com.amazonaws:*</artifact>
                        <includes>
                            <include>**</include>
                        </includes>
                    </filter>
                    <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

当我拿起生成的罐子,解压缩并查看内部时,

➜  geotools git:(dev-S62039_geojson-to-shapefile_ro007848) ✗ pwd                                                                                                                                                                              
/home/ro007848/Workspace/geometry-service/target/jar-shaded-simple/jar-contents/org/geotools                                                                                                                                                  
➜  geotools git:(dev-S62039_geojson-to-shapefile_ro007848) ✗ grep -r "Length"

这就是我发现的:

................
Binary file ows/wms/CRSEnvelope.class matches
Binary file filter/FilterSAXParser.class matches
Binary file filter/FilterDOMParser.class matches
Binary file filter/LengthFunction.class matches
Binary file filter/function/StaticGeometry.class matches
Binary file filter/function/FilterFunction_strLength.class matches
Binary file filter/function/FilterFunction_strToLowerCase.class matches
Binary file filter/function/FilterFunction_strToUpperCase.class matches
Binary file filter/function/FilterFunction_geomLength.class matches
Binary file filter/ExpressionDOMParser.class matches
Binary file referencing/util/CRSUtilities.class matches
Binary file referencing/crs/DefaultProjectedCRS.class matches
................

似乎那里有一个“长度”功能......如果我的例外不是在谈论这个,那么它在谈论哪一个?我该如何调试这个问题?是否有“焦土”方法<include>在 jar-shading 插件配置中设置过滤器,以便使其正常工作?

其他人建议我尝试在着色配置中显式添加这些类,如下所示:

<filter>
    <artifact>org.geotools:gt-main</artifact>
    <includes>
        <include>org/geotools/filter/LengthFunction.class</include>
    </includes>
</filter>

但这要么不起作用,要么我做得不对。

更多信息:

当我在本地对此代码运行集成测试时,执行没有问题。找到所需的任何功能。但是,当我对部署在 AWS 中的资源(由这个 jar 支持的一个 lambda)执行相同的集成测试,我就遇到了失败。我发现很难在调试器中发现很多我需要包含的内容,因为代码似乎是“动态地”做事的,而且我很难密切关注它。

我无计可施!

编辑:我查看了@gerold-broser 发布的电子邮件线程,但我不确定它是否适用,因为根据mvn help:effective-pom -Dverbose我使用的是 geotools 25.1 版。输出说的东西像

      <dependency>
        <groupId>org.geotools</groupId>  <!-- com.digitalglobe.p2020.common:common-dependencies:3.47.139813, line 922 -->
        <artifactId>gt-coverage</artifactId>  <!-- com.digitalglobe.p2020.common:common-dependencies:3.47.139813, line 923 -->
        <version>25.1</version>  <!-- com.digitalglobe.p2020.common:common-dependencies:3.47.139813, line 924 -->
      </dependency>
    ``` and 
    ```
        <dg-geotools.version>25.1</dg-geotools.version>  <!-- com.digitalglobe.p2020.common:common-dependencies:3.47.139813, line 218 -->
    ```


  [1]: https://medium.com/@akhaku/java-class-shadowing-and-shading-9439b0eacb13

标签: javamavenclassloadergeotoolsmaven-shade-plugin

解决方案


正如GeoTools FAQ中所讨论的, GeoTools 依赖于META-INF/services您的应用程序使用的每个 GeoTools 模块中的文件。除非您特别指示Shade插件合并这些文件,否则您最终会得到 maven 看到的第一个或最后一个(我忘记了)。

因此,将其添加到您的 pombuild部分:

       <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>1.3.1</version>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                      <goal>shade</goal>
                  </goals>
                  <configuration>
                      <transformers>
                          <!-- This bit merges the various GeoTools META-INF/services files         -->
                          <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                      </transformers>
                  </configuration>
              </execution>
          </executions>
      </plugin>

如果你想检查它是否有效,那么你需要检查META-INF/services/org.opengis.filter.expression.Function包括org.geotools.filter.LengthFunction


推荐阅读