Humanity

Edit the world by your favorite way

最近の Java EE について調べてみた

私は仕事で Java に関わってきましたが、実質仕事で関わってきたプロジェクトはまだ3~4年ぐらい、 そしてそのプロジェクトの中にはいくつかコードを書く仕事ではなく Excel 仕事がメインというプロジェクトもあり、 正直言うとあまり積極的に Java に関わろうとはしませんでした。

そんな自分が最近、自宅サーバを管理する時にちょっとした Web アプリ(というか Web GUI)がほしいと思って Java で作ろうと思って色々調べた程度のまとまらない文章なので、 以下の文章は沢山の間違いを含むと思います。よって識者の方のコメントをお待ちしています。


最近は(という程最近でもないけど)Java SE 環境でも Java EE の機能がある程度使えるようになってきた。 それを後押しした *1 のが、Spring Boot、 Dropwizard、 WildFly Swarm、Payara Micro 等で UberJAR と呼ばれる実行可能な jar ファイルにできる技術だったりする。 段々とテスタビリティやデプロイの簡便化のためにコンテナレスに向かう一方で、 サーバで動かす分には意識しなかった部分を意識しなければならなかったりする。 そうして Java SE 環境で Java EE なアプリを動かそうとしている中で、やはり Java EEJava EE Server は偉大だという事が分かってきた。

Java EE な Web アプリを作ろうとするとこんな感じのスタックになる。 Java EE はこれらの機能をセットで提供している。 これでもまだ全ての Java EE の機能を使っている訳ではない。

現在のフロントエンド開発環境並みに細かなスタックの組み合わせになっている事がわかる。

EJB抜きのJ2EEにはいったい何が残るというのだ?」と疑問に思われるかもしれない。 答えは「たくさん残るよ。」ということだ。J2EEにはEJBよりはるかにたくさんの価値が含まれている。 多くのJ2EE開発者はそのように考えてはおらず、あなたの机にこの本が置いてあったらEJB抜きのJ2EEは無意味だと言うだろう。 でも、EJBのしていることとJ2EEの全体を客観的に分析するとEJBはもっと重要な全体像のほんの一部に過ぎないことがわかる。

JavaをSEとEEに分類するのは今では無意味になってきている? - 達人プログラマーを目指して

しかし、多言語とちょっと違うのはこれらがライブラリではなく「API」だという事。 API に対する実装はいくつかあり、これがそれぞれの言葉ついての理解やレイヤー等があやふやだと「何の事を言ってんの?」ってなる原因でもある。

実際にそれぞれの API の実装の例を出すとこんな感じ(プロプラなソフトウェアに関しては出していません)。 H2 以外は全て Java EE(正確に言うと JNDI や JDBC は SE らしい)。

  • HTTP Server: Grizzly HTTP Server
  • JAX-RS: Jersey (MOXy)
  • CDI: Jersey (Weld)
    • 関連ファイル:src/main/resources/META-INF/beans.xml
  • JPA: EcliseLink
    • 関連ファイル:src/main/resources/META-INF/persistence.xml
  • JTA: Narayana
  • JNDI Server: JBoss JNP Server
    • 関連ファイル:src/main/resources/jndi.properties
  • DB: H2

上記のスタックは実際に試そうとしたけど、結局 JTA 使うのに JNDI Server が必要? *2 で、色々試したんだけど諦めて WildFly で動かした。

jndi.properties か Java でプロパティを設定すれば JNDI の lookup をサーバーではなくプロパティ値から取ってくるような事もできそうだけど、 そんな SPI (Service Provider Interface) を作ってる人はいませんでした。 これができれば jndi.properties にその設定値を書くだけで完結しそうなので、誰か作ってください。

ちなみに JavaScript の場合の事情は、これらのレイヤーは仕様として固まってない部分もあるのでレイヤーは実際曖昧だったりするけど、 JavaScript について知るにはブラウザや CSS や HTML 等その他様々な物と繋がった知識が必要になり、それらは現在進行形で開発中な所が理解を難しくしている原因だと思う。

あと Java EE のような沢山の仕様を含む仕様を「アンブレラJSR」と言うらしい。 JSR とは Python にとっての PEP とかそんな感じのもの。 PEP にあたるものは JEP というものがあるそうです。 @yy_yank さんありがとうございます! *3 仕様書は PDF で公開されておりダウンロードには Oracle の License Agreement が必要。サンキューオラクル

Java EE に含まれている各 API のバージョンと JSR は Wikipedia のページを見るのが早い。 (Java EE 開発するなら各 API のバージョンはいくつなのかを調べる事があったと思うけど、Wikipedia がここまで詳しい一覧表になっていたのは知らなかった)

Java EE version history - Wikipedia, the free encyclopedia


正直これらの事は最近という程でも全然ないんだけど、あまり追いかけてこなかった。 なぜかというと、まぁ冒頭の私の姿勢の問題が大きいけど、それに加えてやはり Java EE の機能を使うなら Java EE compliant なサーバ(製品はもっと沢山あるけど OSS なら GlassFishWildFly とか)を使った方が楽だから。

派遣エンジニアの私が参画するプロジェクトの顧客や元請けは大企業が多いだろうし、 これから仕事ではまだサーブレットエンジンを使う事になると思う。 政治面や金銭面やサポートや監視等のインフラとか諸々の部分を含めると中々環境を変えづらいというのも分かる。 よって大企業というより、これから少数精鋭で Java の Web アプリを作るような組織だったら Java EE ではないサーバ(Jetty や Grizzly 等)を使う方が適していると思う。

今思いついたメリットを挙げてみる。この他にもあると思う。

  1. 起動が速い
  2. (main() から始まるような)普通の Java アプリケーションに組込みが可能

大体テストしやすそうというのが分かるはず。

ただし、そのための条件として以下が必要となる。

  1. (必須)Java のエラーに対して深い知識を持って(上辺だけではない)対応ができる人がいる
  2. 願わくばその人や周りの環境が知識を広げて伝播してくれるような雰囲気(?)である事

この条件をクリアできるなら上掲したメリットはとても大きいと思う。 具体的にはテストや CI やモチベーション等の意味で。

Java EE に対して全ての機能を知っている人はほぼ存在しないと思われるので、 大体の人が Java EE サーバに抱く感想は「(何やってるのかわかんないけど)重くて思い通りに動いてくれない」だと思う。 自分も沢山の事をやってくれるのは何となく理解したけど、やっぱり重いのは嫌だ。 あとデプロイエラーになった時とかサーバとコードどっちに原因があるのか分からず ひたすら色んなツールのキャッシュクリアを試みた思い出とか思い出したくない。 そういったトラウマを抱えているのは自分だけではないと思うんだけど、 自分の場合 Jetty や Grizzly を起動した時の速さを目の当たりにしてちょっと克服できた。 Jetty、Grizzly かわいい。Weld(CDI)かわいい Jersey(JAX-RS)かわいいとなってようやく Java に抵抗がなくなってきた。 完全な知識理解はボトムアップでしか成しえないと思うので、 それぞれのコンポーネントを理解していると、他製品の理解にも繋がる。


tyru.hatenablog.com

これまた最近知った事で、JNDI 名はコンテナによりベース?の文字列が結構バラバラだったりする。 GlassFishjava:app/ とか Wildflyjava:jboss/ ?とか。 なので JNDI 名は省略せずフルで指定した方がいい。 ポータビリティ的な観点でフルで指定するよりも省略したほうがいいのかな、とか思ったりしたけど、それよりも環境によって変わってしまい動かなくなる事の方が問題。 まぁサーブレットエンジンを変えたら大体そのままのコードでは動かないけど、 フルで指定しているとエラーメッセージも分かりやすかったりして、特定が楽になる。

冒頭でも言ったけど、正直仕事で Java を使ってきたのに、あまり趣味では Java を使ってこなかった。 Java を趣味で使うようになったのは最近なので、こういった基礎的な事柄が抜けているなと感じる。 JNDI とかは既にプロジェクトのコードや初期の環境構築で設定済みになっている事が多い。

こういった基礎的な事柄だけど、基礎だからこそフレームワークミドルウェアによって隠される事は(Java には特に)多い気がする。 なので、自分で一から手を動かして物を作らないと分からない事って沢山あるなと痛感したのでした(小並)。

関連リンク

追記:JTA 諦めてローカルトランザクションで動かした方がいい?

jBatch RI を Java SE でまともに(JPA,CDI,Transactionalつきで)動かす #javaee - kencharosの日記

JTA@Transactional が使いたい場合は、この記事の方が書かれてるように、自分で実装しちゃうのが一番の解決策な気がします。

あと EntityManager が @PersistenceContext 経由で取れないのも Java SE 特有のあるある問題らしく、 自分も諸先輩方を見習ってプロデューサーで解決したのですが、スレッドローカルにするのは思いつきませんでした。 というか JTA 動かすのに精一杯で確かプロデューサーのクラスが @Dependant で inject 対象のクラスが @ApplicationScoped になってました。 EntityManager はスレッドセーフではないので潜在的なバグを抱えてた事になります。怖い。

*1:というよりも Java SE 環境で使う手段が大体これなので、同時に整備されてきたという理解が正しい?

*2:あと JMS を使うにも必要っぽい?使ってないけど

*3:https://twitter.com/yy_yank/status/778984326402674688 http://yyyank.blogspot.jp/2015/04/javajsr.html