最近のアーキテクチャ界隈の話題と言えば、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」モジュールのフットプリント的にもずいぶん違ってくるはずです。