You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让AWS Lambda支持Spring Boot应用部署与运行报错排查

问题背景

目标

现有一个Spring Boot应用,需要适配AWS Lambda运行。

需求

构建可直接上传至Lambda函数的jar包,通过API Gateway调用该函数时,返回和本地执行java -jar启动应用完全一致的响应结果。


已完成配置
  • 已编写@RestController接口,同时创建Lambda请求处理类StreamLambdaHandler.java,代码如下:
package mypackage;

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class StreamLambdaHandler implements RequestStreamHandler {
    private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
    static {
        try {
            handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(MyClass.class); // MyClass是应用中执行SpringApplication.run的启动类
        } catch (ContainerInitializationException e) {
            e.printStackTrace();
            throw new RuntimeException("Could initialize Spring framework", e);
        }
    }

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        handler.proxyStream(inputStream, outputStream, context);
        outputStream.close();
    }
}
  • 已将该类的handleRequest方法配置为Lambda函数执行入口,配置截图
  • 使用AWS SAM部署,编写的sam.yaml配置如下:
AWSTemplateFormatVersion: '2010-09-09'                                                       
Transform: AWS::Serverless-2016-10-31
Description: AWS Serverless Spring Boot API - Spring Boot API PrycePick
Resources:
  SpringbootSampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler:  pryce_pick.search.StreamLambdaHandler::handleRequest
      Runtime: java11
      CodeUri: out/artifacts/myfunction/my.zip
      MemorySize: 512
      Policies: AWSLambdaBasicExecutionRole
      Timeout: 30
      Events:
        GetResource:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: any

Outputs:
  SpringbootSampleApi:
    Description: URL for application
    Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/'
    Export:
      Name: SpringbootApp
  • 执行的部署命令如下:
aws cloudformation package --template-file sam.yaml --output-template-file output-sam.yaml --s3-bucket mybucket
aws cloudformation deploy --template-file output-sam.yaml --stack-name bookApi --capabilities CAPABILITY_IAM

故障现象

构建包含全量依赖的jar包后,在AWS控制台Lambda测试界面验证:

对应报错日志片段:

ationTypeMapping.java:102)
at org.springframework.core.annotation.AnnotationTypeMappings.addIfPossible(AnnotationTypeMappings.java:112)
at org.springframework.core.annotation.AnnotationTypeMappings.addIfPossible(AnnotationTypeMappings.java:105)
at org.springframework.core.annotation.AnnotationTypeMappings.addMetaAnnotationsToQueue(AnnotationTypeMappings.java:99)
at org.springframework.core.annotation.AnnotationTypeMappings.addAllMappings(AnnotationTypeMappings.java:79)
at org.springframework.core.annotation.AnnotationTypeMappings.<init>(AnnotationTypeMappings.java:68)
at org.springframework.core.annotation.AnnotationTypeMappings.<init>(AnnotationTypeMappings.java:46)
at org.springframework.core.annotation.AnnotationTypeMappings$Cache.createMappings(AnnotationTypeMappings.java:245)
at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(Unknown Source)
at org.springframework.core.annotation.AnnotationTypeMappings$Cache.get(AnnotationTypeMappings.java:241)
at org.springframework.core.annotation.AnnotationTypeMappings.forAnnotationType(AnnotationTypeMappings.java:199)
at org.springframework.core.annotation.AnnotationTypeMappings.forAnnotationType(AnnotationTypeMappings.java:182)
at org.springframework.core.annotation.AnnotationTypeMappings.forAnnotationType(AnnotationTypeMappings.java:169)
at org.springframework.core.annotation.TypeMappedAnnotations$IsPresent.doWithAnnotations(TypeMappedAnnotations.java:330)
at org.springframework.core.annotation.TypeMappedAnnotations$IsPresent.doWithAnnotations(TypeMappedAnnotations.java:279)
at org.springframework.core.annotation.AnnotationsScanner.processClassHierarchy(AnnotationsScanner.java:188)
at org.springframework.core.annotation.AnnotationsScanner.processClassHierarchy(AnnotationsScanner.java:171)
at org.springframework.core.annotation.AnnotationsScanner.processClass(AnnotationsScanner.java:106)
at org.springframework.core.annotation.AnnotationsScanner.process(AnnotationsScanner.java:86)
at org.springframework.core.annotation.AnnotationsScanner.scan(AnnotationsScanner.java:77)
at org.springframework.core.annotation.TypeMappedAnnotations.scan(TypeMappedAnnotations.java:242)
at org.springframework.core.annotation.TypeMappedAnnotations.isPresent(TypeMappedAnnotations.java:98)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:144)
at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169)
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:132)
at com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler.handleRequest(SpringBootLambdaContainerHandler.java:52)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxy(LambdaContainerHandler.java:163)
at com.amazonaws.serverless.proxy.internal.LambdaContainerHandler.proxyStream(LambdaContainerHandler.java:198)
at mypackage.StreamLambdaHandler.handleRequest(StreamLambdaHandler.java:29)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at lambdainternal.EventHandlerLoader$StreamMethodRequestHandler.handleRequest(EventHandlerLoader.java:375)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:899)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:262)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:199)
at lambdainternal.AWSLambda.main(AWSLambda.java:193)
END RequestId: 29d504dc-3510-4d78-b010-3fe48a4e6f13
REPORT RequestId: 29d504dc-3510-4d78-b010-3fe48a4e6f13  Duration: 2278.06 ms    Billed Duration: 2279 ms    Memory Size: 512 MB Max Memory Used: 106 MB Init Duration: 940.24 ms

解决方案

报错是依赖版本不匹配+配置路径错误+打包方式错误共同导致的,按以下步骤修改即可:

  1. 修正适配包依赖
    日志里的注解扫描异常,是因为引错了aws-serverless的适配包。使用Spring Boot 2.x必须引入aws-serverless-java-container-springboot2依赖,Spring Boot 3.x对应引入aws-serverless-java-container-springboot3,不要使用不带版本号的通用spring包,该包仅兼容Spring Boot 1.x,和高版本Spring搭配必然出现注解扫描错误。Java11+Spring Boot 2.7.x环境下,适配包选1.9.3版本即可,Maven依赖示例:
    <dependency>
        <groupId>com.amazonaws.serverless</groupId>
        <artifactId>aws-serverless-java-container-springboot2</artifactId>
        <version>1.9.3</version>
    </dependency>
    
  2. 修正Handler配置路径
    代码里StreamLambdaHandler属于mypackage包,但sam.yaml中配置的Handler路径是pryce_pick.search.StreamLambdaHandler::handleRequest,包名完全不匹配,Lambda无法加载到正确的处理类,修改为实际包名对应的路径:
    Handler: mypackage.StreamLambdaHandler::handleRequest
    
  3. 修正打包方式
    不要把jar包额外压缩成zip上传,Lambda原生支持Spring Boot打出来的fat jar。使用Spring Boot官方maven插件打包,生成的jar包直接作为CodeUri即可,不需要二次压缩。打包插件配置示例:
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.12</version>
                <configuration>
                    <mainClass>mypackage.MyClass</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
    执行mvn clean package后,直接将target目录下生成的jar路径配置为CodeUri即可。
  4. 冷启动优化(可选)
    在application.properties中增加配置,避免Spring启动时初始化内置Tomcat,缩短冷启动时间:
    spring.main.web-application-type=none
    

以上配置修改完成后重新打包部署,接口即可正常响应,返回结果和本地java -jar启动完全一致。


内容的提问来源于stack exchange,提问作者אמיר שקדי

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:42:17