在AWS Lambda中运行Spring Boot应用

30 10月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/10/30/run-spring-boot-in-aws-lambda/

AWS Lambda 是一种计算服务。首先将代码上传到 AWS Lambda ,它按使用时间收费,有自动伸缩等功能,也就是说你上传了代码,其他事情你就不用管了。

从字面上看你上传的代码是一个函数,那么就需要一个触发器来调用你的函数。AWS提供了若干触发器,其中就有API Gateway。这意味着你可以暴露一个HTTP或者HTTPS的调用地址,然后执行对应的函数。

因为AWS Lambda有自己的一些要求,所以很明显是无法直接运行Spring Boot应用的,需要修改一下入口才能实现对应的功能。

首先在依赖中加入aws的依赖

compile group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.48'

这个依赖中包含了我们必须实现的接口RequestHandler

package com.amazonaws.services.lambda.runtime;

import com.amazonaws.services.lambda.runtime.Context;

/**
 * 
 * Lambda request handlers implement AWS Lambda Function application logic using plain old java objects 
 * as input and output.
 *
 * @param <I> The input parameter type
 * @param <O> The output parameter type
 */
public interface RequestHandler<I, O> {
    /**
     * Handles a Lambda Function request
     * @param input The Lambda Function input
     * @param context The Lambda execution environment context object.
     * @return The Lambda Function output
     */
    public O handleRequest(I input, Context context);
}

所以新建一个Runner类

@Configuration
@EnableAutoConfiguration
@ComponentScan("你自己的包名")
public class Runner implements RequestHandler<Void, PersonsVO> {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private static ConfigurableApplicationContext applicationContext;

    @Override
    public PersonsVO handleRequest(Void input, Context context) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        logger.info("Start !");
        ApplicationContext applicationContext = getApp();
        logger.info("Spring boot load finished.");
        stopWatch.stop();
        logger.info("Time is {}", stopWatch.toString());
        T t = applicationContext.getBean(你需要的类.class);
        return t.function();
    }

    private ConfigurableApplicationContext getApp() {
        if (applicationContext == null) {
            applicationContext = new SpringApplicationBuilder()
                    .main(getClass())
                    .bannerMode(Banner.Mode.OFF)
                    .web(false)
                    .sources(getClass())
                    .addCommandLineProperties(false)
                    .build()
                    .run();
        }
        return applicationContext;
    }
}

其实原理很简单,因为入口变了,所以只有自己启动Spring上下文,然后调用。

AWS Lambda标榜的是自己调用了就会回收,但是从观察来看,似乎会保持当前的环境和状态一段时间,所以我们可以再调用的时候先判断一下有没有Spring上下文,如果有就直接使用,没有才加载。

首次请求真的很慢,因为Spring需要生成上下文,如果你还用了hibernate这些,那启动速度轻轻松松达到10s,但是这之后的时间就很快了,因为环境中已经有Spring上下文了。如果很久之后你的函数再被触发,那么又需要重新加载了。

aws-lambda

总的来说一个普通的Spring Boot应用是很难直接迁移到AWS Lambda的,虽然能够工作,但是响应时间和包大小很难接受。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2016/10/30/run-spring-boot-in-aws-lambda/

发表回复

您的电子邮箱地址不会被公开。