Spring BootをAWS Lambdaで動かす – (2)HanderクラスをApplication Contextとして指定する

2016.05.25

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回、Spring BootをAWS Lambdaで動かす方法について書きました。今回も同じテーマなのですが「@Autowired」アノテーションを使用してComponentのインスタンスを取得する、よりSpring Bootらしい実装ができたので、それについて書きたいと思います。

実装について - 今回変わったところ

「@Autowired」アノテーションなどSpringの機能を使用するため、今回はLambdaのHandlerを実装するクラスをSpringのApplication Contextとして指定しました。以下に、今回変更があったクラスについて記述します。

1.RequestHandler

Lambdaのエントリーポイントとなるhanderを実装するクラスです。先にも書いたように、このクラスをApplication Contextとして指定します。

LambdaFunctionHandler.java
package com.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

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

import lombok.Setter;

@SpringBootApplication
public class LambdaFunctionHandler implements RequestHandler<Object, Object>{

    @Autowired
    private SampleBean sampleBean;
    
    @Autowired
    private ConfigReader configReader;
    
    @Setter
    private Object input;
    
    @Setter
    private Context context;
    
    @Override
    public Object handleRequest(Object input, Context context) {
        context.getLogger().log("-----start.-----");
        String args[] = new String[0];
        try (ConfigurableApplicationContext ctx = SpringApplication.run(LambdaFunctionHandler.class, args)) {
            LambdaFunctionHandler app = ctx.getBean(LambdaFunctionHandler.class);
            app.setInput(input);
            app.setContext(context);
            app.run(args);
            context.getLogger().log("-----end.-----");
            return "success.";
        } catch (Exception e) {
            e.printStackTrace();
            context.getLogger().log("error.\n");
            return "error.";
        }
    }

    public void run(String... args) throws Exception {
        String inputValue = sampleBean.sampleMethod(input.toString());
        context.getLogger().log(inputValue);
        
        context.getLogger().log("Region = " + configReader.getRegion());
        context.getLogger().log("Bucket = " + configReader.getBucket());
        context.getLogger().log("file = " + configReader.getFile());
    }
}

handlerを持つクラスに対して、13行目で「@SpringBootApplication」アノテーションを付与してSpring Bootとして開始できるようにしています。32・33行目でこのクラスをApplication Contextとし、36行目でrunメソッドを呼び出しています。行いたい主な処理は、このrunメソッド内に記述することになります。

またrunメソッド内でLambdaのhandlerが取得する2つの変数「input」「context」を使用するため、34・35行目でSetterを呼び出してセットしています。なお「input」「context」にはlombokの「@Setter」アノテーションを付与することで、Setterを自動的に生成しています。

runメソッド内で使用したい2つのCompornent「SampleBean」「ConfigReader」は、16・19行目で「@Autowired」アノテーションを付与して宣言しています。これにより、Springにより自動的にインスタンスが作成されることになります。

2.Applicationクラス

前回はApplicationクラス内に、Beanを取得するメソッドを用意しました。今回は「@Autowired」アノテーションでBeanのインスタンスは取得するため、そのメソッドは削除します。実際は上記のhanderより起動するため、Lambdaでの実行だけを考慮すれば必要ないクラスかもしれません。

Application.java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3.ConfigReaderクラス

前回はConfigReaderクラス内でComponentのインスタンスを取得するため、先に削除したApplicationクラスのBeanを取得するメソッドを呼び出していました。今回は「@Autowired」アノテーションでComponentのインスタンスを取得します。以下のソースの9行目がその箇所です。

ConfigReader.java
package com.example;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ConfigReader {
    @Autowired
    private Settings settings;
     
    public String getRegion(){
        return settings.getRegion();
    }
     
    public String getBucket(){
        Map<String, String> map = settings.getS3();
        return map.get("bucket");
    }
     
    public String getFile(){
        Map<String, String> map = settings.getS3();
        return map.get("file");
    }
}

まとめ

handerを実装するクラスをApplication ContextとしてSpringを起動することで、「@Autowired」アノテーションを使用することができました。なお、残りのソースについては前回を参照してください。