如何通过AWS SAM部署monorepo中依赖同仓库Gradle模块的Lambda项目
SAM的Java Gradle构建流程存在天然的沙箱逻辑:执行构建前,只会把单个函数模块对应的CodeUri目录整体拷贝到隔离的临时构建路径,不会主动追溯配置文件中指向外部目录的跨级子项目路径。
在抽离commons共享模块之前,所有业务代码都集中在单个函数模块的CodeUri目录下,SAM拷贝的源码范围和Gradle构建的引用路径完全匹配,所以构建流程不会出现异常。
你当前的配置是每个函数模块单独维护settings.gradle,通过../../commons的跨级相对路径引用共享模块——等源码被拷到临时沙箱后,这个../../commons的路径已经跳出了SAM实际拷贝的文件范围,Gradle自然找不到commons模块的源码,最终在执行jar任务时抛出找不到commons.jar的异常。
1. 重构Gradle多项目配置逻辑
彻底废弃每个函数模块单独维护settings.gradle、跨级引用共享模块的模式,把多项目声明逻辑统一收敛到monorepo的最根目录:
- 删除所有函数子目录下独立存在的
settings.gradle文件,避免每个子目录单独成为独立的Gradle根项目 - 在monorepo最外层根目录新建统一的
settings.gradle,基于根目录的相对路径声明所有子项目,不存在跨出根目录的路径引用:
// monorepo根目录/settings.gradle rootProject.name = "lambda-service-monorepo" // 声明全部纳入管理的子项目 include ':commons', ':function-user', ':function-order', ':function-pay' // 基于根目录的相对路径绑定各模块位置,不使用跨上级目录的引用 project(':commons').projectDir = file('commons') project(':function-user').projectDir = file('functions/user-function') project(':function-order').projectDir = file('functions/order-function') project(':function-pay').projectDir = file('functions/pay-function')
- 保留每个函数模块
build.gradle里的implementation project(":commons")依赖声明,这部分和本地Gradle构建的逻辑完全一致,不需要修改。
2. 调整SAM构建上下文范围
修改template.yaml配置,把原本指向单个函数子目录的CodeUri调整为整个monorepo的根目录,让SAM在拷贝沙箱源码时把所有子模块(包括commons共享模块)全部纳入拷贝范围,同时通过Metadata配置指定每个函数要执行的Gradle构建任务:
# template.yaml 核心配置示例 Globals: Function: Runtime: java17 MemorySize: 1024 Timeout: 30 # 构建上下文直接指向monorepo根目录,确保整个代码库都会被拷贝到临时沙箱 CodeUri: . Metadata: BuildMethod: gradle Resources: UserFunction: Type: AWS::Serverless::Function Properties: Handler: com.example.user.Handler::handleRequest # 保留函数对应的部署产物路径,和Gradle shadowJar的输出路径匹配 CodeUri: build/libs/user-function.jar Metadata: # 单独给当前函数指定对应的Gradle构建参数 BuildGradleArgs: "clean :functions/user-function:shadowJar" OrderFunction: Type: AWS::Serverless::Function Properties: Handler: com.example.order.Handler::handleRequest CodeUri: build/libs/order-function.jar Metadata: BuildGradleArgs: "clean :functions/order-function:shadowJar"
3. 常见避坑点
- 不要在Gradle配置中使用跳出monorepo根目录的相对路径引用,比如跨级的
../../路径,这类路径一旦不在SAM的拷贝范围内,就会复现找不到模块的问题 - 打Lambda部署包时优先使用
shadowJar插件,避免普通jar任务无法把commons模块的代码打包进最终部署产物的问题 - 本地测试时可以先执行
sam build --debug,检查临时沙箱目录下是否包含完整的commons模块源码,确认拷贝范围符合预期后再执行部署。
注:调整完成后,本地Gradle构建的逻辑不会发生任何变化,和原有的开发流程完全兼容;SAM构建时因为整个代码库都在沙箱内,多项目依赖的解析逻辑和本地完全一致,不会再出现找不到共享模块的异常。
内容的提问来源于stack exchange,提问作者Cole Schafer

