将 Spring boot/cloud 与 Amazon AWS lambda 结合使用不会注入值

我有一个 AWS lambda 类,它由 AWS 直接调用。最终,我需要让它与Spring Boot一起使用,因为我需要它能够从Spring Cloud配置服务器检索数据。RequestHandler

问题在于,如果我从自己的开发环境本地运行代码,但无法在 AWS 上部署时注入配置值,则代码可以正常工作

@Configuration
@EnableAutoConfiguration
@ComponentScan("my.package")
public class MyClass implements com.amazonaws.services.lambda.runtime.RequestHandler<I, O> {
   public O handleRequest(I input, Context context) {
        ApplicationContext applicationContext = new SpringApplicationBuilder()
                .main(getClass())
                .showBanner(false)
                .web(false)
                .sources(getClass())
                .addCommandLineProperties(false)
                .build()
                .run();

        log.info(applicationContext.getBean(SomeConfigClass.class).foo);
        // prints cloud-injected value when running from local dev env
        //
        // prints "${path.to.value}" literal when running from AWS 
        //    even though Spring Boot starts successfully without errors
   }
}

@Configuration
public class SomeConfigClass {
   @Value("${path.to.value}")
   public String foo;
}

src/main/resources/bootstrap.yml:
spring:
  application:
    name: my_service
cloud:
  config:
    uri: http://my.server
    failFast: true
    profile: localdev

我试过了什么:

  • 使用常规的Spring MVC,但这没有@Value注入/Spring Cloud集成
  • 使用 - 但发现它不支持.yml文件@PropertySource
  • 验证以确保配置服务器正在向任何IP地址提供请求(没有IP地址过滤)
  • 运行以确保价值恢复curl
  • 验证以确保.jar实际上包含在罐根bootstrap.yml
  • 验证以确保.jar实际包含 Spring Boot 类。FWIW 我正在使用 Maven 阴影插件,它将项目打包成一个包含所有依赖项的胖.jar。

注意:AWS Lambda 不支持环境变量,因此我无法设置类似的东西 (既不作为环境变量也不作为参数)。我也无法控制实际启动的基础类 - 这对最终用户是完全透明的。我只是打包罐子并提供入口点(类名),其余的都照顾好了。spring.application.name-DMyClass

有什么我可以错过的吗?有什么方法可以更好地调试它吗?


答案 1

经过一些调试,我已经确定问题出在使用Maven Shade插件上。Spring Boot在其自动配置jar中查找META-INF / spring.factories jar,请参阅此处以获取相关信息。为了正确打包Spring Boot jar,您需要使用Spring Boot Maven插件并将其设置为在maven重新打包阶段运行。它在本地 IDE 中工作的原因是,您没有运行 Shade 打包 jar。他们在插件中做一些特殊的魔术,把东西放在Shade插件不知道的正确位置。

我能够创建一些示例代码,这些代码最初没有注入值,但现在我使用了正确的插件, 这些代码可以正常工作。请参阅此 GitHub 存储库,了解我所做的工作。

我没有将其与Spring Cloud连接,但现在Spring Boot注入的其余部分正在工作,我认为它应该很简单。

正如我在评论中提到的,您可能只需要考虑一个简单的REST调用来获取云配置并自己注入它,以节省为每个请求加载Spring应用程序的开销。

更新:对于Spring Boot 1.4.x,您必须在Spring Boot插件中提供以下配置:

            <configuration>
                <layout>MODULE</layout>
            </configuration>

如果您不这样做,那么默认情况下,插件的新行为是将所有jar放在BOOT-INF下,因为目的是使jar可执行并让bootstrap进程加载它。我在解决为此处遇到的情况添加警告时发现了这一点。请参阅 https://github.com/spring-projects/spring-boot/issues/5465 以供参考。


答案 2

推荐