キクタローさんから「Javaエンジニア養成読本」という本をいただきました。ありがとうございます。
というわけで、JavaEEがらみ、キクタローさんのエントリに乗っかる形の記事を書いてみました。
実はJavaEE方面のエントリを書くのは今年初めて、去年の夏以来だったりします。かなり間が空きましたね。時間がほしいです。誰か仕事手伝ってください。バイトとかいないかねー。
この間にリリースされたものにSpringFramework 4があります。もうすぐでてから1年で、そろそろ使っても問題ないころ合いだと思います。
また、政治面の問題でSpringを使わなければならないというところもかなり多いと思います。JavaEEの技術を使ってみたいと思ってもフルの機能に乗っかるわけにはいかない状況もあるでしょう。
しかし、JavaEEを構成する要素の中でも、もっとも人気の高いJAX-RSならば組み合わせて利用するのも問題は少ないでしょう。最初のバージョン1.0からかなり実用的でした。そしてSpringは本来のDIコンテナのみに集中してもらうのです。これならば社内のライブラリなどSpringベースの資産も問題なく組み込むことができます。
現在のサーバーサイドJavaではずばりベストの組み合わせは
Spring + JAX-RS
だと思います。政治方面、技術方面とあわせてのバランスが一番取れていて説得しやすい形だと思います。アプリケーションサーバーに左右されませんし、設定によっては軽い開発、スタンドアロンのテストなども可能です。
今回はせっかくなのでSpringBootを使います。JAX-RSの実装はRIのJerseyです。JerseyのスタンドアロンサーバーにSpringを組み込むという方法もあると思いますが、今回はこちらで。どちらにしろ、実際の運用はアプリケーションサーバー上になるでしょうから、開発しやすいものを探すとよいでしょう。
SpringBootのセットアップ
こちらを参照してください。
http://kikutaro777.hatenablog.com/entry/2014/11/20/010828
起動できたら終わり。キクタローさんありがとう(*´▽`*)ノ゛
Jerseyを組み込む
プロジェクトツリーから「依存性」を右クリック、「依存性を追加」を選択します。
以下のダイアログが表示されますので、jersey-spring-3のver2.13を探し、追加します。
プログラムの構造
いよいよコードを書きます。
今回のプログラムは足し算です。http://localhost:8080/rest/add/12/34とうちこんだら、12+34という計算をするといったものになります。とりあえずレスポンスはtext/plainで。
先に構造書いた方がわかりやすいのでのせますが、すべてのソース構成は以下のようになります。
上から順に解説します。
logicパッケージ
実際の足し算をするクラスが一つだけあります。足し算くらいならこんな分け方は必要ないのですが、実際はここがデータベースアクセスなどが来るものと思ってください。
restパッケージ
URLへのマッピング、リソース部分です。ここがJAX-RSの領域です。
JerseyConfigクラス
JAX-RSの実装であるJerseyの環境設定部分です。packagesはサブパッケージも検索します。
Mainクラス
SpringBootの設定、起動部分です。コンポーネントスキャンのパスを設定しています。Jerseyサーブレットをrestというパスにマッピングしています。CalcRest#addのパスと併せて「http://localhost:8080/rest/add/a/b」となるわけですね。
見てわかるとおり、全部Javaコードで、設定ファイルはありません。
ソース
CalcLogic.java
package com.mycompany.springboottest.logic; import org.springframework.stereotype.Component; @Componentpublicclass CalcLogic { publicint add(int a, int b){ return a + b; } }
CalcRest.java
package com.mycompany.springboottest.rest; import com.mycompany.springboottest.logic.CalcLogic; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/") publicclass CalcRest { @Inject CalcLogic calcLogic; @GET@Produces(MediaType.TEXT_PLAIN) @Path("add/{a}/{b}") publicint add( @PathParam("a") int a, @PathParam("b") int b){ return calcLogic.add(a, b); } }
JerseyConfig.java
package com.mycompany.springboottest; import org.glassfish.jersey.filter.LoggingFilter; import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.spring.scope.RequestContextFilter; import org.springframework.context.annotation.Configuration; @Configurationpublicclass JerseyConfig extends ResourceConfig{ public JerseyConfig() { register(RequestContextFilter.class); register(LoggingFilter.class); packages("com.mycompany.springboottest.rest");//リソースクラスの保存先 } }
Main.java
package com.mycompany.springboottest; import org.glassfish.jersey.servlet.ServletContainer; import org.glassfish.jersey.servlet.ServletProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @EnableAutoConfiguration@ComponentScan(basePackages = { "com.mycompany.springboottest.logic"} ) publicclass Main { @Beanpublic ServletRegistrationBean jerseyServlet() { ServletRegistrationBean registration = new ServletRegistrationBean( new ServletContainer(), "/rest/*"); registration.addInitParameter( ServletProperties.JAXRS_APPLICATION_CLASS, JerseyConfig.class.getName()); return registration; } publicstaticvoid main(String[] args) { SpringApplication.run(Main.class, args); } }
JAX-RSのリソースクラスにはコンポーネントスキャン設定をしなくても見てくれているようなので、省いています。
実行
ブラウザを開き、アドレスバーに http://localhost:8080/rest/add/12/34を入力します。
実際にSpringBootで開発する場合ですが、差分デプロイの仕方がわからなかったため毎回起動しているとさすがに遅いです。5,6秒もかかってしまいます。これだとTomcatに普通にデプロイするほうがサクサク開発できそうという感じでした。
というわけで、SpringとJAX-RSの組み合わせのお話でした。さくさく楽々開発しましょう。