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

Posted

技术标签:

【中文标题】将 Spring boot/cloud 与 Amazon AWS lambda 一起使用不会注入值【英文标题】:Using Spring boot/cloud with Amazon AWS lambda does not inject values 【发布时间】:2016-07-05 01:28:59 【问题描述】:

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

问题是代码如果我在我自己的开发环境中本地运行可以工作,但在 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,但这是 doesn't have integration with @Value injection/Spring cloud。 使用 @PropertySource - 但发现它不支持 .yml 文件 经过验证以确保配置服务器正在为任何 IP 地址的请求提供服务(没有 IP 地址过滤) 运行 curl 以确保恢复值 已验证以确保 .jar 在 jar 根目录中实际包含 bootstrap.yml 已验证以确保 .jar 实际包含 Spring Boot 类。 FWIW 我正在使用 Maven shade 插件,它将项目打包成一个包含所有依赖项的胖 .jar。

注意:AWS Lambda 支持环境变量,因此我不能设置类似spring.application.name 的任何东西(既不能作为环境变量,也不能作为-D 参数)。我也无法控制实际启动MyClass 的底层类——这对最终用户是完全透明的。我只是打包jar并提供入口点(类名),剩下的就处理好了。

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

【问题讨论】:

您的配置服务器是否可以从“外部”获得?我的意思是,你确定它没有隐藏在 IP 保护或类似的东西后面吗? @freakman 好点,但不 - 刚刚检查过,配置请求是从任何主机提供的。 我假设您已经看过这个:cloud.spring.io/spring-cloud-aws/…,但它不适合您?我对 AWS Lambda 了解不多,但看到了这篇文章:github.com/cagataygurturk/aws-lambda-java-boilerplate。也许您已经检查了这些但想确认。 @RobBaily 谢谢,aws-java-lambda-boilerplate 正在使用经典的 Spring .xml 应用程序上下文方法(请参阅AbstractHandler.java:58),但正如我在帖子中提到的那样,它没有与@Value 注入/Spring cloud 集成(而 Spring Boot 可以)。回复:文档 - 是的,我在我的 Maven cfg 中使用spring-cloud-config artifactId,不幸的是,文档中没有提到 lambda,所以我无法从那里获得太多信息。 @mindas 您是否尝试过在本地为 Spring Cloud 类设置日志级别,您可以在其中看到它在做什么?如果是这样,那么您可以为您的 Lambda 部署设置相同的日志记录级别,看看有什么不同。不确定有多少日志可用,但您也可以克隆它并添加自己的日志消息。 【参考方案1】:

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

我能够创建一些最初没有注入值但现在我使用了正确的插件的示例代码。请参阅this GitHub repo 以查看我所做的事情。

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

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

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

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

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

【讨论】:

Spring Boot Maven Plugin 是缺少的元素。我不得不稍微调整一下设置,但整个组合都奏效了。有趣的事实是,根据日志,引导程序需要 10 秒(!)——这绝对是不鼓励在 AWS 环境中使用 Spring Boot 的一个因素。不过,感谢您的辛勤工作,非常感谢! @mindas 是的,我认为 Spring Boot 在他们的容器环境之一中可能比 Lambda 更有意义。当这种情况发生时,我还将看到有关提出某种类型警告的请求,因为它绝对不明显并且可能在其他情况下发生。 好消息是,Amazon 会在丢弃 Lambda 实例之前将其保持一段时间(未定义?),因此可以使用相同的实例来处理下一个请求。这意味着代码应该检查应用程序上下文是否已经初始化,如果是则跳过它。也就是说,对于频繁的请求,开销问题是无关紧要的。 我收到了 1.5.7.RELEASE 的警告:Module layout is deprecated. Please use a custom LayoutFactory instead. 我对此不太关心,但它似乎是这里的参考docs.spring.io/spring-boot/docs/1.5.x-SNAPSHOT/reference/… 如果您在使用新的 Spring Boot 版本时遇到问题,您可能需要发布一个单独的问题。

以上是关于将 Spring boot/cloud 与 Amazon AWS lambda 一起使用不会注入值的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Spring Boot mybatis分布式微服务云架构使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程

Spring Cloud Spring Boot mybatis分布式微服务云架构使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程

Spring Initializr 构建Spring Boot/Cloud工程

Spring/Boot/Cloud系列知识:SpringMVC进行HTTP信息接收和发送的过程

Spring boot cloud vault 更新到 3.0.3 版本后不再加载属性

Spring/Boot/Cloud系列知识:SpringMVC进行HTTP信息接收和发送的过程