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 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 ping() {

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

        Map 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

你可能感兴趣的:(AWS Serverless部署java api(LAMBDA篇))