SpringBoot + Vert.x(3.0.0) + SqlTemplate を試す


## はじめに
[Vert.x](http://vertx.io/)のv3がリリースされたので、[SpringBoot](http://projects.spring.io/spring-boot/)の中からVert.xを使って、[Bootiful SQL Template](https://github.com/cero-t/sqltemplate)
を利用してみた。ソースは[こちら](https://github.com/muraken720/springboot-vertx)。
## コンセプト
- SpringBootを使ってJavaアプリケーションを作成する。
- Vert.xはSpringBootアプリケーションの中でembeddedの形で使う。

## プロジェクト構成

```
├── pom.xml
└── src
    └── main
        ├── java
        │   └── muraken
        │       └── example
        │           ├── Application.java
        │           ├── HttpServerVerticle.java
        │           ├── SqlTemplateService.java
        │           ├── SqlTemplateVerticle.java
        │           └── entity
        │               ├── Dept.java
        │               └── Emp.java
        └── resources
            ├── application.properties
            ├── data.sql
            ├── schema.sql
            └── sql
                ├── selectAll.sql
                ├── selectByArgs.sql
                ├── selectByEmpno.sql
                └── selectByParam.sql
```

## pom.xml
[pom.xml](https://github.com/muraken720/springboot-vertx/blob/master/pom.xml)にはVert.x、SpringBoot、SqlTemplate、Jacksonを追加。
長いので、リンク先参照。

## Application.java
Vert.xのVerticleを@Beanで登録してみる。SqlTemplateはJDBCアクセスするblocking codeなので、SqlTemplateをラップするSqlTemplateVerticleはWorkerVerticleとしてdeployする。

```java:Application.java
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

  @Bean
  SqlTemplate sqlTemplate(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
    return new SqlTemplate(jdbcTemplate, namedParameterJdbcTemplate);
  }

  @Bean
  ObjectMapper jsonMapper() {
    return new ObjectMapper();
  }

  @Bean
  SqlTemplateVerticle sqlTemplateVerticle() {
    return new SqlTemplateVerticle();
  }

  @Bean
  HttpServerVerticle httpServerVerticle() {
    return new HttpServerVerticle();
  }

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

    final Vertx vertx = Vertx.vertx();

    vertx.deployVerticle(context.getBean(SqlTemplateVerticle.class), new DeploymentOptions().setWorker(true));
    vertx.deployVerticle(context.getBean(HttpServerVerticle.class));

  }
}
```

## HttpServerVerticle.java
HttpServerを立ち上げて、リクエストが来たらEventBusを使って、SqlTemplateVerticleにメッセージを送信し、レスポンスをそのまま画面に返す。

``` java:HttpServerVerticle.java
@Component
public class HttpServerVerticle extends AbstractVerticle {

  public void start() {
    console("start.");

    vertx.createHttpServer().requestHandler(req -> {
      console("Received a http request");

      vertx.eventBus().send("eb.sqltemplate", "findAll req", ar -> {
        if (ar.succeeded()) {
          console("Received reply: " + ar.result().body());
          req.response().end((String) ar.result().body());
        }
      });
    }).listen(8080);
  }

  private void console(String message) {
    System.out.println("[" + Thread.currentThread().getName() + " ] " + getClass().getName() + " : " + message);
  }
}
```

## SqlTemplateVerticle.java
SqlTemplateを利用するSqlTemplateServiceをインジェクションしてもらう。JacksonのObjectMapperもそうしたけど、これはNGかも。
EventBusからメッセージが来たら、SqlTemplateServiceを呼び出して、結果をJSONに変換してリプライを返すようにしている。
Vert.xのJsonObjectは取り回しがやりづらく、結局JSONで扱うなら、Stringでもよいのではないかと。

``` java:SqlTemplateVerticle.java
@Component
public class SqlTemplateVerticle extends AbstractVerticle {

  @Autowired
  private SqlTemplateService sqlTemplateService;

  @Autowired
  private ObjectMapper jsonMapper;

  public void start() throws JsonProcessingException {
    console("start.");

    vertx.eventBus().consumer("eb.sqltemplate", message -> {
      console("Received a message: " + message.body());

      List<Emp> emps = this.sqlTemplateService.findAll();

      try {
        String json =this.jsonMapper.writeValueAsString(emps);
        message.reply(json);
      } catch (JsonProcessingException e) {
        e.printStackTrace();
      }
    });
  }

  private void console(String message) {
    System.out.println("[" + Thread.currentThread().getName() + " ] " + getClass().getName() + " : " + message);
  }
}
```

## SqlTemplateService.java
こちらは[Bootiful SQL Template](https://github.com/cero-t/sqltemplate)から抜粋で拝借。 ~~2Way SQLですよ。~~

``` java:SqlTemplateService.java
@Component
public class SqlTemplateService {
  @Autowired
  SqlTemplate template;

  public List<Emp> findAll() {
    return template.forList("sql/selectAll.sql", Emp.class);
  }
}
```

## 実行
通常のJavaアプリケーションとして実行できる。Java8が必要。
実行したら```localhosto:8080```にアクセスする。

```
mvn package

java -jar target/springboot-vertx-example-1.0.0.jar
```

起動すると SqlTemplateVerticleがWorkerThreadで、HttpServerVerticleがEventLoopThreadで動作しているのが分かる。

```
2015-06-25 00:27:00.858  INFO 73715 --- [           main] muraken.example.Application              : Started Application in 4.783 seconds (JVM running for 6.034)
[vert.x-worker-thread-0 ] muraken.example.SqlTemplateVerticle : start.
[vert.x-eventloop-thread-4 ] muraken.example.HttpServerVerticle : start.
```

続けて```localhost:8080```にアクセスすると次のようになる。

```
[vert.x-eventloop-thread-4 ] muraken.example.HttpServerVerticle : Received a http request
[vert.x-worker-thread-1 ] muraken.example.SqlTemplateVerticle : Received a message: findAll req
2015-06-25 00:28:38.357 DEBUG 73715 --- [worker-thread-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL query
2015-06-25 00:28:38.358 DEBUG 73715 --- [worker-thread-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [select
    *
from
    emp]
[vert.x-eventloop-thread-4 ] muraken.example.HttpServerVerticle : Received reply: [{"empno":7369,"ename":"SMITH","job":"CLERK","mgr":7902,"hiredate":345826800000,"sal":800.0,"comm":null},{"empno":7499,"ename":"ALLEN","job":"SALESMAN","mgr":7698,"hiredate":351442800000,"sal":1600.0,"comm":300.0},{"empno":7521,"ename":"WARD","job":"SALESMAN","mgr":7698,"hiredate":351615600000,"sal":1250.0,"comm":500.0},{"empno":7566,"ename":"JONES","job":"MANAGER","mgr":7839,"hiredate":354985200000,"sal":2975.0,"comm":null},{"empno":7654,"ename":"MARTIN","job":"SALESMAN","mgr":7698,"hiredate":370450800000,"sal":1250.0,"comm":1400.0},{"empno":7698,"ename":"BLAKE","job":"MANAGER","mgr":7839,"hiredate":352220400000,"sal":2850.0,"comm":null},{"empno":7782,"ename":"CLARK","job":"MANAGER","mgr":7839,"hiredate":347814000000,"sal":2450.0,"comm":null},{"empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":408207600000,"sal":3000.0,"comm":null},{"empno":7839,"ename":"KING","job":"PRESIDENT","mgr":null,"hiredate":374770800000,"sal":5000.0,"comm":null},{"empno":7844,"ename":"TURNER","job":"SALESMAN","mgr":7698,"hiredate":368722800000,"sal":1500.0,"comm":0.0},{"empno":7876,"ename":"ADAMS","job":"CLERK","mgr":7788,"hiredate":411145200000,"sal":1100.0,"comm":null},{"empno":7900,"ename":"JAMES","job":"CLERK","mgr":7698,"hiredate":376153200000,"sal":950.0,"comm":null},{"empno":7902,"ename":"FORD","job":"ANALYST","mgr":7566,"hiredate":376153200000,"sal":3000.0,"comm":null},{"empno":7934,"ename":"MILLER","job":"CLERK","mgr":7782,"hiredate":380559600000,"sal":1300.0,"comm":null}]
```

何回かブラウザでアクセスすると、HttpServerVerticleは常に```vert.x-eventloop-thread-4```で動作するのに対して、SqlTemplateVerticleは```vert.x-worker-thread-1```の1の部分が、2, 3, 4...となり、スレッドが変わることが分かる。

## 感想
- Vert.x v3のリリースおめでとうございます！
- SpringBoot、data.sqlとschema.sqlが超便利！（そこ？）
- EventBusを使ってnon blockingな非同期メッセージング処理が簡単に書ける
- 今回やってないけど、cluster組むのもEventBusがあるから簡単。
- [Bootiful SQL Template](https://github.com/cero-t/sqltemplate)は ~~2Way SQLで~~ 堅くて良いよね。