AWS Serverless部署java api(LAMBDA篇)

本文承接RDS for MySQL,前面我们已经部署好了数据库服务,并测试了连通性,这里则开始部署我们的代码,并连通rds服务.

可以以官方demo为例,或者引入aws提供的aws-serverless-java-container-spring组件,进行部分改造即可。

官方github:GitHub - awslabs/aws-serverless-java-container: A Java wrapper to run Spring, Jersey, Spark, and other apps inside AWS Lambda.

这里介绍如何在我们的工程里添加lambda支持,我们的已有工程为Spring框架,首先在pom.xml中引入serverless依赖.

image

接着需要添加StreamLambdaHandler.class,SpringApiConfig.class.

image

两者功能在这里简单介绍一下,RequestStreamHandler是aws lambda 应用程序的入口,我们声明的StreamLambdaHandler继承了RequestStreamHandler,并加载了初始化时,需要扫描的方法类,这些类都在SpringApiConfig中注解引入。

RequestStreamHandler.class


public class StreamLambdaHandler implements RequestStreamHandler {

    private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;

    static {

        try {

            handler = SpringLambdaContainerHandler.getAwsProxyHandler(SpringApiConfig.class);

        } catch (ContainerInitializationException e) {

            // if we fail here. We re-throw the exception to force another cold start

            e.printStackTrace();

            throw new RuntimeException("Could not initialize Spring framework", e);

        }

    }

    @Override

    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)

            throws IOException {

        handler.proxyStream(inputStream, outputStream, context);

    }

}

在SpringApiConfig中,一次性引入多个需要调用的方法类,否则发布程序后,lambda将无法读取到相应的类。

SpringApiConfig.class:


@Configuration

// We use direct @Import instead of @ComponentScan to speed up cold starts

// @ComponentScan("my.service.controller")

@Import({ PingController.class, TestController.class, DataSyncController.class})

public class SpringApiConfig {

    /*

     * Create required HandlerMapping, to avoid several default HandlerMapping instances being created

     */

    @Bean

    public HandlerMapping handlerMapping() {

        return new RequestMappingHandlerMapping();

    }

    /*

     * Create required HandlerAdapter, to avoid several default HandlerAdapter instances being created

     */

    @Bean

    public HandlerAdapter handlerAdapter() {

        return new RequestMappingHandlerAdapter();

    }

    /*

     * optimization - avoids creating default exception resolvers; not required as the serverless container handles

     * all exceptions

     *

     * By default, an ExceptionHandlerExceptionResolver is created which creates many dependent object, including

     * an expensive ObjectMapper instance.

     *

     * To enable custom @ControllerAdvice classes remove this bean.

     */

    @Bean

    public HandlerExceptionResolver handlerExceptionResolver() {

        return new HandlerExceptionResolver() {

            @Override

            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

                return null;

            }

        };

    }

}

配置完以后,开始配置我们真正的逻辑代码,上两个例子,程序员的好朋友hello word,与简单的jdbc链接查询。

PingController.class:


@Controller

@EnableWebMvc

public class PingController {

   @Autowired

   TestService testService;

    @RequestMapping(path = "/ping", method = RequestMethod.GET)

    public Map<String, String> ping() {

        System.out.println("controoler ping ");

        Map<String, String> pong = new HashMap<>();

        pong.put("pong", "Hello, World!");

        return pong;

    }

    @RequestMapping(path = "/getMySql", method = RequestMethod.GET)

    public Map getMySql() {

        Map results = new HashMap<>();

        ResultSet resultSet = null;

        try {

            MysqlConnnect mysqlConnnect = new MysqlConnnect();

            Connection con = mysqlConnnect.getRemoteConnection();

            System.out.println("Remote connection successful.");

            String sql = "SELECT * FROM test t where t.desc like ?";

            PreparedStatement preparedStatement = con.prepareStatement(sql);

            preparedStatement.setString(1, "%1%");

            resultSet = preparedStatement.executeQuery();

            List resultList = new ArrayList();

            while (resultSet.next()) {

                Map map = new ConcurrentHashMap();

                map.put("id",resultSet.getInt("id"));

                map.put("name",resultSet.getString("name"));

                map.put("desc",resultSet.getString("desc"));

                resultList.add(map);

            }

            // 释放资源

            if (resultSet != null) {

                resultSet.close();

            }

            if (preparedStatement != null) {

                preparedStatement.close();

            }

            if (con != null) {

                con.close();

            }

            results.put("msgCode",200);

            results.put("msg","");

            results.put("data",resultList);

        }catch (Exception e){

            System.out.println("SQLException:" + e.toString());

            results.put("msgCode",500);

            results.put("msg",e.toString());

            results.put("data","");

        }finally{

            return results;

        }

    }

}

MysqlConnnect.class:


public class MysqlConnnect {

//    static Logger logger = LogManager.getLogger(MysqlConnnect.class.getName());

    @Autowired

    private RdsMysqlInfo rdsMysqlInfo;

    public Connection getRemoteConnection() {

        System.out.println("getRemoteConnection:");

        try {

            Class.forName("com.mysql.cj.jdbc.Driver");

            String jdbcUrl = "jdbc:mysql://hostname:port/dbname?user=&password=";//数据库关键信息自己补充

            System.out.println("jdbcUrl" + jdbcUrl);

            System.out.println("Getting remote connection with connection string from environment variables.");

            Connection con = DriverManager.getConnection(jdbcUrl);

            System.out.println("Remote connection successful.");

            return con;

        } catch (ClassNotFoundException e) {

//            logger.warn(e.toString());

            System.out.println("ClassNotFoundException:" + e.toString());

        } catch (SQLException e) {

//            logger.warn(e.toString());

            System.out.println("SQLException:" + e.toString());

        }

        return null;

    }

}

编写完之后,执行打包命令 mvn compile package ,这里我们的包叫core,正常情况下,我们发布到其他服务例如tomcat,weblogic之类的都需要使用war包,但lambda上我们需要使用classes.jar,另外将需要使用的jdbc jar包打入classes.jar中。

尽管lambda有layers层功能可以加载到所依赖的所有jar包,但实际上对jdbc这个jar的引用并没有起作用╮(╯▽╰)╭

image
image

以上代码层已经准备完全。开始在lambda上面创建我们的function。

进入Lambda服务,选择创建函数,运行语言环境为java 8,角色选择现有角色,这个角色是我在IAM中已经创建好了,包含了lambda创建,apigateway创建,role创建等等一系列的权限,假如没有相应的权限,后面会有相应的提示,到时候加上即可。

image

在新的控制面板中,选择新创建的函数,在下方的函数代码中,上传我们的core-classes.jar,运行语言为java 8,处理程序填写规则为package.{ClassName}::{FunctionName},我这里package是service.controllers className是PingController 方法名是getMySql,这个很好理解吧,填完之后选择右上角保存。

image

由于新创建的lambda服务还没加入到与数据库的同一安全组内,所以此时是无法访问数据库服务的,在此我们把它加进去:

选择与rds for mysql同一vpc,并至少选择两项子网组,子网组跟地域有一定的关系,aws会默认生成,选择两项即可,安全组选择同一安全组。

image

接下来我们需要测试我们上传的api是否有效,选择配置测试事件,可以自定义传入的报文内容,配置完之后保存,回到主面板页面执行测试。

image

修改处理程序里的functionname为ping,保存,测试ping方法,hello world 它leile.

image

修改处理程序里的functionname为getMySql,保存,测试,毫无悬念。至此lambda发布java api配置完成,后面将阐述如何将api通过api-gateway发布至公网。

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容