首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用来自多版本JAR的不正确的类文件的AWS Lambda?

使用来自多版本JAR的不正确的类文件的AWS Lambda?
EN

Stack Overflow用户
提问于 2021-05-07 20:13:19
回答 2查看 1.3K关注 0票数 1

我在Java8下运行了几年的lambda,我刚刚将它更新为Java11。它立即崩溃,给我带来了如下错误:

代码语言:javascript
复制
Caused by: java.lang.ExceptionInInitializerError
    at com.mycompany.rest.providers.JsonProvider.writeTo(JsonProvider.java:80)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:242)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:227)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:139)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1116)
    at org.glassfish.jersey.client.ClientRequest.doWriteEntity(ClientRequest.java:461)
    at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:443)
    at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:367)
    at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:265)
    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:297)
    ... 15 more
Caused by: java.lang.UnsupportedOperationException: No class provided, and an appropriate one cannot be found.
    at org.apache.logging.log4j.LogManager.callerClass(LogManager.java:571)
    at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:596)
    at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:583)
    at com.mycompany.rest.util.NonClosingOutputStream.<clinit>(NonClosingOutputStream.java:11)
    ... 25 more

所讨论的类并不特别令人兴奋,并且具有在我的类中常见的简单的静态初始化:

代码语言:javascript
复制
public class NonClosingOutputStream extends ProxyOutputStream {
    private static final Logger log = LogManager.getLogger(); // Line 11

    public NonClosingOutputStream(final OutputStream proxy) {
        super(proxy);
    }

    ...

当我将我的(非Lambda) java服务器从8切换到11时,我曾见过类似的问题;我需要将jar的清单标记为Multi-Release: true,因为我所依赖的ApacheLog4j工件为Java8和9+中的org.apache.logging.log4j.util.StackLocator类提供了替代实现。但是,我某种程度上希望JVM只获取这个类的适当版本。有什么我必须设置的配置吗?是否有可能将我的Lambda从Java8 -> Java 11中切换到某个地方?

jar/META-INF/versions:

代码语言:javascript
复制
versions/
├── 11
│   └── org
│       └── glassfish
│           └── jersey
│               └── internal
│                   └── jsr166
│                       ├── JerseyFlowSubscriber$1.class
│                       ├── JerseyFlowSubscriber.class
│                       ├── SubmissionPublisher$1.class
│                       ├── SubmissionPublisher$2.class
│                       ├── SubmissionPublisher$3.class
│                       ├── SubmissionPublisher$4.class
│                       ├── SubmissionPublisher$5.class
│                       ├── SubmissionPublisher$6.class
│                       ├── SubmissionPublisher.class
│                       └── SubmissionPublisherFactory.class
└── 9
    ├── module-info.class
    └── org
        └── apache
            └── logging
                └── log4j
                    ├── core
                    │   └── util
                    │       └── SystemClock.class
                    └── util
                        ├── Base64Util.class
                        ├── ProcessIdUtil.class
                        ├── StackLocator.class
                        └── internal
                            └── DefaultObjectInputFilter.class

编辑:I正在找到参考文献,指示当AWS提取JAR时,它们不解压META目录,该目录包含MANIFEST.MF文件,该文件告诉JVM JAR是一个Muli发布JAR。兰巴斯支持多释放罐吗?

EN

回答 2

Stack Overflow用户

发布于 2021-06-15 00:47:33

对你的问题不完全是一个答案,但我希望这可能会有所帮助。

您的分析是正确的- AWS提取整个JAR文件。然后运行lambda函数的JVM不再将代码识别为JAR文件,实际上忽略了整个META目录。

在我的例子中,我使用maven-shade-plugin创建了一个包含lambda函数所有依赖项的"uber"-jar。在正式AWS文件中推荐这种方法。现在--这一点很重要-- maven-shade-plugin提取所有jar文件依赖项并将它们重新打包到一个单一的平面jar文件中。如果您的依赖项之一是一个多版本jar (和log4j2一样),那么您可以配置maven-shade-plugin来重构一个适当的META目录,如果您将jar 作为jar文件运行,那么一切都仍然可以工作。但是由于AWS Lambda提取jar,JVM不再“看到”META目录,而元INF/版本中的任何内容都会被忽略。

为了解决这个问题,我切换到了maven-assembly-plugin。它允许使用lambda的代码创建ZIP文件,并将依赖项添加为JAR文件。现在,当AWS Lambda提取这个ZIP文件时,JAR保持不变,一切正常。

若要配置此文件,请创建如下所示的文件assembly.xml

代码语言:javascript
复制
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>zip</id>
    <!-- Make sure the ZIP contents are not nested in a subdirectory -->
    <includeBaseDirectory>false</includeBaseDirectory>

    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
        <fileSet>
            <directory>${project.basedir}/conf</directory>
        </fileSet>
        <!-- Include the compiled classes as-is and put them in the root of the ZIP -->
        <fileSet>
            <directory>${project.build.directory}/classes</directory>
            <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
    <dependencySets>
        <!-- Include all dependencies in the lib/ directory -->
        <dependencySet>
            <outputDirectory>lib</outputDirectory>
            <excludes>
                <exclude>${project.groupId}:${project.artifactId}:jar:*</exclude>
            </excludes>
        </dependencySet>
    </dependencySets>
</assembly>

然后您需要在您的maven-assembly-plugin中配置pom.xml

代码语言:javascript
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.3.0</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptors>
                    <descriptor>assembly.xml</descriptor>
                </descriptors>
                <finalName>${project.artifactId}</finalName>
            </configuration>
        </execution>
    </executions>
</plugin>

现在,只需将生成的zip文件像往常一样部署到AWS Lambda上,瞧!

顺便提一句--虽然带有阴影的JAR文件包含数千个单独的.class文件,但组装的ZIP文件只包含少数JAR文件。即使整体大小(以字节为单位)更大,文件的数量也会更少,从而减少冷启动时间。我还没有在AWS上测试过这一点,但是在我的LocalStack上,冷启动时间从1分降到了6秒--这对开发来说无疑是一个很好的助推器。

票数 4
EN

Stack Overflow用户

发布于 2021-06-14 19:49:04

根据我的AWS帐户代表,AWS Lambdas不支持这个时候的多版本JAR (2021-06-14)。我需要重新配置我的pom来构建多个工件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67441142

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档