谷本 心 in せろ部屋

はてなダイアリーから引っ越してきました

Spring Boot + MOA その1 - Spring BootでMicroserviceのクライアント/サーバを実装している途中の話

最近のアーキテクチャ界隈の話題と言えば、Microservice。
MSAと略すかMOAと略すか、みたいな議論もあるようですが、
CEROMETAL的にはMOAを一押しせざるを得ない状況です。
MOAMETAL - google画像検索


いいとして。


システムをMicroservice的に設計すると、小さな粒度のWebサービスができあがります。
そしてこのWebサービス間の通信をするためには、
HTTPなりAMQPなりのプロトコルを使ったリモートサービス呼び出しが必要となります。


SOA的に考えれば、ESBやCamelのようなメッセージングバスを利用するという仕組みもアリですが、
もう少しライトに、簡単なHTTPコールで呼び出しを済ませたいと思うことも多いでしょう。


今回はその辺りをゼロベースで考えて「僕が考える最強のリモートサービス呼び出し」を見つけるべく、
実装しながら試行錯誤したので、その辺りの過程を記録しておきます。


なお、サンプルソースは全部githubに上げています。
https://github.com/cero-t/moa-sample

まずはシンプルにRestTemplateと@RestControllerで実装。

まずはシンプルに、サーバ側はSpring Bootの@RestControllerを使ったサービス実装とし、
クライアント側はRestTemplateを使うことにします。


まずサーバ側から。こんなStudentクラスを作ります。
https://github.com/cero-t/moa-sample/blob/master/moa-sample-1/student-domain-1/src/main/java/domain/Student.java

public class Student {
    public Integer id;
    public String name;
    public Integer score;
}

見ての通り、public field厨です、サーセンww


次に、Studentを使ったControllerを実装します。
https://github.com/cero-t/moa-sample/blob/master/moa-sample-1/student-service-1/src/main/java/application/controller/StudentController.java

@RestController
public class StudentController {
    @RequestMapping(value = "/student", method = RequestMethod.GET)
    public Student get() {
        Student student = new Student();
        student.id = 1;
        student.name = "TEST";
        student.score = 100;
        return student;
    }

    @RequestMapping(value = "/student", method = RequestMethod.POST)
    public int post(Student student) {
        return 1;
    }
}

かなり適当な実装ですがいいとして。


そしてクライアント側の実装です。
https://github.com/cero-t/moa-sample/blob/master/moa-sample-1/student-client-1/src/main/java/StudentClient.java

public class StudentClient {
    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<Student> result = restTemplate.getForEntity("http://localhost:8080/student", Student.class);
        Student student = result.getBody();
        System.out.println(student.id);
        System.out.println(student.name);
        System.out.println(student.score);

        Integer value = restTemplate.postForObject("http://localhost:8080/student", student, Integer.class);
        System.out.println(value);
    }
}

URLにlocalhost:8080の直書きとか、もう、しびれる感じの実装ですね!


これでひとまず、Webサービスの呼び出しができあがります。
ほら、簡単でしょう?

モジュールは「サービス実装」と「サービスインタフェース(入出力)」で分けるべき。

ところで、僕はWebサービスの「サーバ側」を実装をする際に、
2つのモジュールに分割するようにしています。

- domain : 引数や戻り値のクラスを集めたモジュール
- service : サービス実装本体のモジュール


上の例で言えば、
「Student」クラスは「domain」モジュールに含まれて、
「StudentController」クラスは「service」モジュールに含まれます。


そうすることで「StudentClient」クラスは「domain」モジュールのみに依存し、
「service」モジュールには依存しないような構成を取ることができます。
それで「client」モジュールのフットプリント的にもずいぶん違ってくるはずです。

ここまでのまとめ

すごく簡単な形ですが、シンプルなWebサービス呼び出しができました。
また、サーバ側は「domain」「service」に分けることで、
インタフェース側と実装側に分離する形を取りました。


ただこの実装では、
あまりにもHTTPによる通信が実ソースに表れすぎですし、
サーバ側のAPIは「自分がどこから呼ばれるのか」を知るすべがありません。


次回はこの辺りの課題を解決すべく、
Service interfaceを導入する方向を検討してみます。


Stay metal, see you!