LoginSignup
36
28

More than 3 years have passed since last update.

Jakarta EEをはじめよう!

Last updated at Posted at 2020-11-30

Advent Calendarの第1日目です

 2014年に「Java EEを始めよう!」を投稿してから6年、当時の多くのプレーヤーが消えたり、交代したりする中で、Java EEはJakarta EEになって再登場しました。そこで、最近「わかりやすいJakarta EE」という本を出しました。ウェブシステムの作り方を解説した本です。

 Java言語初心者でも読めるJakarta EEの本というコンセプトなんですが、そもそも「Java EEとかJakarta EEとか言われても・・・」と思う人、多いでしょうね。
 そこで、今日は、Jakarta EEのあれこれをいろいろお話します。
 Jakarta EE未経験者のためのガイダンスです。
 この記事を通じて、「わたしもやってみよう」と思ってもらえれば幸いです。

はじめのはじまり

 Javaを使ってずいぶんになります。まだ、Javaコンパイラに日本語が通らない頃、"write once , run anywhere"ということばにひかれてやってみたのが最初でした。Javaでソケット通信の小さなプログラムを作ってみました。これが違うOSのマシンであっけなく動いたので、「こりゃすごい」と感動したのでした。

 Appletでもいろいろ試してみましたが、当時は起動に10分くらいかかったので、実用にはなりませんでした。が、しばらくしてservletが登場したので状況が違ってきました。servletは、新しい時代の匂いがしていましたね。

 ただその後のJ2EEは、とても触る気になれなかったので、(暇だったこともあって)「自分用のフレームワークを作ってみよう」と思い、1年ほどかけてJEF(Java Easy Framework)というのを作りました。JEFは10年ほど前まで開発を続けていて、eラーニングシステムなどの多くのシステム開発に使いました。

 と、と、ところが、そのうちに世の中は大きく変わっていたのです。JEFのおかげで、Strutsなどは眼中になかったのですが、グプタさんのビデオを見てとても驚きました。ここまで便利になってしまうとは!それが、わたしがJava EE、そしてJakarta EEに取り組むはじまりでした。 

JSFはやさしい!

 やはりJSFですね。これがJakarta EEをやりたい最初の動機です。とにかくウェブとのデータのやり取りや画面遷移が簡単です。
 図で説明しましょう。次の図をご覧ください。
 

011500.jpg

 『わかりやすいJakarta EE/3章ウェブアプリケーションの仕組み』より

左端の「バッキングビーン」というのがJavaプログラム、右側の「JSFページ」はJSFの画面(上段)、「Facelets」はそのソースコード(下段)です。
 

ウェブとJavaプログラムとのデータ受け渡しがカンタン

 まず、下段のFaceletsですが、h:などが付いていますが気にしないでください。おおむねHTMLと同じようなタグです。このようなタグはFaceletsタグといい、ウェブ画面を作るのに使います。もちろん、HTMLとの混在も可能です。FaceletsはHTMLを知っていればすぐに理解できます。
 
 図のFaceletsは番号や氏名の入力欄のために、テキスト入力領域を定義しています。
h:inputText ・・・というあたりです。
この中で、value="#{meiboBean.number}" の部分がポイントです。
この{#・・・}の部分をEL式といい、Javaプログラムの変数との対応付けを行っています。

 例えば、#{meiboBean.number}は、番号の入力値を左端のMeiboBeanというJavaプログラムの、numberというフィールド変数と対応づけるという意味です。また、#{meiboBean.name}は、名前の入力値を同じくnameというフィールド変数に対応づけています。

 そうです、これだけで、ウェブで入力したデータがプログラムに渡されるのです。プログラム側では、原則、何もする必要はありません。逆に、プログラムで変数に値が入っていれば、それがウェブに表示されます。ウェブ上の項目とJavaプログラムの変数とを結びつけるこの仕組みを、バインドといいます。
 バインドは単純ですが、とても強力な機能です。これがあるからJSFを使いたいと思わせるインパクトがあります。
 

ページナビゲーションがカンタン

 次に注目するのは、Faceletsの送信ボタンです。h:commandButtonと書いてあるやつです。
これが送信ボタンを表示するFaceletsタグです。
 ボタン定義の中に、action="#{meiboBean.next()}" というEL式があります。これは、送信ボタンを押したときに実行する、Javaプログラムのメソッドを指定しています。

 実際に、左端のJavaプログラムにはpublic String next() があります。送信ボタンが押されると、データを受け取った上で、さらにこのnextメソッドを実行するわけです。nextメソッドでは、実際にはフィールド変数をデータベースに保管するなどの操作をします。そして最後にreturn文で、次に表示するウェブ画面のファイル名を返します。これがページナビゲーションです。これだけで、次の画面(output.xhtml)が開きます。
 
106.jpg

 面倒な設定ファイルはありません。だたこれだけです。このreturn文で指定するだけというシンプルさは本当に脱帽ものですね。
ちなみに、動作を確実にするには、

MeiboBean.java
return "output.xhtml?faces-redirect=true"

のように、末尾に?faces-redirect=trueを付けます。
これを付けないと、画面遷移が不安定に(バグも含めて)なることがあるので、注意です。

ちなみに、同じ画面を再表示するには、return null; または、return ""; です。あるいは、メソッドを戻り値のないvoid型にしても同じです。  

ウェブとJavaプログラムとの連携もカンタンです

このように、ウェブ画面(JSFページ)とバインドするJavaプログラムは、クラス定義の先頭に@Namedというアノテーションを付けるだけで設定できます。設定ファイルなんてありません。いろいろ書かなくても、決まりきったアノテーションを付けるだけでよいようにしよう、というのがJakarta EEの方向性ですから。ちなみに、@RequestScopedは、バッキングビーンの生存期間(寿命と理解しましょう)を決めるアノテーションです。ほかにもまだいくつかありますが、これは、「1回のリクエストとレスポンスの間だけ存在する」という、最も短い寿命を指定する場合に使います。
なお、このようにJavaオブジェクトに寿命を与えるアイデアは、後でお話するCDIに関連しています。
 

システムの使用感を実際に動いているサイトで体験してください

「わかりやすいJakarta EE」では、21章でショッピングサイトを作成します。これを、動かして公開していますので、触ってみたい方は次のURLにアクセスしてください。

 <雑貨屋さん.com>http://k-webs.jp:8080/zakka-ya-san/faces/index.xhtml

使用したライブラリを除くと、Javaのソースコードは、わずか350行程度ですが、買い物をしてカートに入れ、注文までできます。簡単に書けますが、やはり、JSFの力が大きいです。特に動的に表を描く機能(h:dataTableタグを使います)はすぐれモノです。本でも詳しく解説しています。
 
 ・注文すると確認メールが届きます。(実際に購入はできません)
 ・ログインしなくても買い物はできますが、ログインすると購入履歴が見れます。
  (ログインIDは本に書いてありますので見てください)
 ・データベースはページ単位のアクセス制御をしています。
 ・画像はデータベースから直接取り出して表示しています。

データベース(JPA)もやさしい

 Javaでデータベースと言えば、JDBCを使ってというのが相場でした。例えば、お話したJEFは、DAOパターンのクラス群のソースコードをデータベースのスキーマから自動生成する機能があり、それなりに便利でした。しかし、JPAを知ってしまうと、それはほとんど「おもちゃ」のようなものだったと分かったのでした。

テーブル作成がカンタン

 JPAの核心はORM(オブジェクト関係マッピング)です。名前は堅苦しいですが、中身は単純です。
 
 さて、ORMは簡単にいうと、オブジェクトを含むレコードをそのまま、データベースに記録できるようにする方法です。これは、SQLをよく知っていれば、「そんなアホな話!」と驚くところです。というのも、関係データベースにはオブジェクト型はありません。RDBは、Javaでいう基本データ型の世界ですから。

 例えば、次のような(かなり作為的ですが)テーブルがあるとき、従来だとすぐにテーブル生成のSQLを書きますね。
1つは顧客表(CUSTOMERテーブル)、もう一つは顧客の追加情報表(INFORMATIONテーブル)です。そして、2つのテーブルを関連付けたいので、顧客表には追加情報キーのフィールドがあります。
キーで関連付けるのはRDBではごく普通のやり方です。
 

顧客番号 氏名 追加情報キー
cus001 田中宏 1
cus002 鈴木太郎 2
cus003 斎藤圭子 3
追加情報キー 住所 電話番号 携帯番号
1 東京都 03-333-3333 090-333-3333
2 大阪府 06-666-6666 090-666-6666
3 福岡市 092-999-9999 090-999-9999

 
しかし、JPAを利用すると、そもそもこのようなテーブルは考えなくてもいいのです。これは、オブジェクト指向の世界ではありません。JPAでは、テーブルを直接操作するのではなく、レコードの内容を表す簡単なオブジェクト(エンティティといいます)を使うだけです。エンティティを作成するには、@Entityアノテーションを付けた次のようなクラスを作ります。エンティティは、フィールド変数とセッター、ゲッターがあるだけの単純なクラスです。エンティティクラスのフィールド変数がそのまま、データベースのフィールド(カラム)に対応すると考えてください。
 

Customer.java
@Entity
public class Customer implements Serializable {
    @Id
    private String customerId;
    private String name;
    private Information info;
    // コンストラクタ(省略)
  // アクセサメソッド(省略)
}

 
 これはCustomerクラス(顧客エンティティ)です。そして、これからCustomer型のオブジェクトを作ることができ、また、CUSTOMERという名前のデータベーステーブルを自動作成して、オブジェクトを保管できます。ただ、注意すべきは、CustomerクラスにInformation型の変数があることです。いいのでしょうか?Infoはオブジェクトですけどね。

 ところが、ここがJPAのエライところで、このままでいいのです。エンティティを作っただけで何もしていませんが、エンティティの中にあるInformationオブジェクトは、自動的にデータベースのテーブル(INFORMATIONテーブル)に展開されます(テーブルは自動的に作られ、関係を示す外部キー項目も自動生成されます!)。なんと、すばらしいですね(^_^;

 繰り返して言っておきますが、物理的なデータベーステーブルを直接操作するイメージは捨ててください。JPAでは、テーブルのレコードではなく、エンティティオブジェクトを読み書きするのです。
 なお、当然ですが、次のようなInformationエンティティも作成しておく必要があります。
  

Information.java
@Entity
public class Information implements Serializable {
    @Id
    private Long id;
    private String address;
    private String phone;
    private String cellular;

    // コンストラクタ(省略)
  // アクセサメソッド(省略)
}

(レコードに当たる)エンティティの保存がカンタン

 データベースにレコードを保存するのはどうするのかというと、たとえて言うと、JavaでListに要素を入れたり出したりするような、あんな感じです。JDBCベースの操作よりもうんと簡単です。

 それはJPAがエンティティマネジャーという、読み書きなどを行うためのオブジェクトを用意しているからです。エンティティマネージャーのメソッドを使うと、新規登録(persist)、更新(merge)、削除(remove)、検索(find)などが行えますが、実は、NetBeansがエンティティクラスからそのようなメソッド群を自動生成してくれます。それを使うだけですから、DOAを作る手間すら必要ない、というわけです。
 
 具体的には、エンティティ(オブジェクト)だけ作って、後は自動生成されるDAOクラスのaddメソッドで保存するだけです。保存の操作は、バッキングビーンで行います。バッキングビーンは、冒頭にもでてきましたが、画面とのデータの受け渡しやデータベースへの保存、読み出しなどを行うJavaプログラムです。
 

MeiboBean.java
@Named
@RequestScoped
public class MeigoBean {
    // 途中省略
    @Inject
    CustomerFacade  db;  // DAO(データベース処理を行う)、自動生成されるのでInjectするだけ
    // 途中省略
    public void create(){
        //
        Information info1 = new Information(1, "東京都", "03-333-3333", "090-333-3333");
        Customer c1 = new Customer("cus001", "田中宏", info1);
        db.add(c1);
        //
        Information info2 = new Information(2, "大阪府", "06-666-6666", "090-666-6666");
        Customer c2 = new Customer("cus002", "鈴木太郎", info2);
        db.add(c2);
    }
}

 
 上記のCustomerFacade db;の部分が、データベース処理を実行するためのDAOオブジェクトです。宣言だけしているように見えますが、Jakarta EEでは@Injectというアノテーションを付けるだけで、CustomerDb型のオブジェクトを変数dbに代入してくれます。オブジェクトをnewでつくらなくてもよいので最初は不思議な感じですが、すぐになれます。便利ですし。
 
 それでdb.add()メソッドでオブジェクトをデータベースに登録します。これだけです。簡単ですね。特に、「データベースを操作している」という感じがしないほどです。「普通にオブジェクトを作って、データベースにaddした」と、そういう感覚でよいわけです(List操作みたいです)。
 
 おっと、ひとつ忘れるところでした。
 上記では、Customerエンティティに当たるc1を保存すると、同時にInfomationエンティティにあたるinfo1も保存されます。これをカスケードといいます。そして、カスケードするには、先ほどのエンティティで、実際に保存する方に、マッピングアノテーションを追加する必要があります。ここでは、実際に保存操作を行ったのはCustomerの方ですから、Customerエンティティのinfoフィールドにアノテーションを付けてカスケードの指定をします。
 

Customer.java
@Entity
public class Customer implements Serializable {
    @Id
    private String customerId;
    private String name;
    @OneToOne(cascade = {CascadeType.ALL})
    private Information info;
    // コンストラクタ(省略)
  // アクセサメソッド(省略)
}

 @OneToOneというアノテーションがでてきました。ここではカスケード指定のために使っています。カスケード指定は、CRUDのすべての操作でカスケードするためにCascade.ALLを指定します。これ以外に、特定の動作だけに限定する指定もあります。
 ともあれ、ここまでの説明で、SQLやJDBCの操作が全く出てこないことがわかったかと思います。エンティティオブジェクトを初めて保存する時、RDBのテーブルは自動的に作成されます。結局、JPAではJavaオブジェクトをそのまま扱うだけです。とてもスッキリしていますね。もうJDBCのガチな世界には戻る気がしません。
 

もっと複雑なケースでもカンタン

 上記の例は、One-to-One(1対1)の関係という、最も単純なORMの例でした。これ以外に、例えば、所属と社員の関係のように、所属オブジェクトがフィールドに社員のListを持つ場合は、One-to-Many(1対多)の関係になります。また、大学で多くの学生が、それぞれいろいろな科目を受講する場合、学生オブジェクトは科目のListをもち、科目オブジェクトは学生のListを持つのでMany-to-Many(多対多)の関係です。

 RDBでは外部キーや結合テーブルでこれらの関係を表しますが、JPAではそれを意識する必要はありません。JPAが自動的にテーブルと外部キー、結合テーブルを作成して処理するので、プログラマは、そんなことは忘れて構いません。Javaベースのプログラムだけで考えればよいのです。
 つまり、データベーステーブルで考えるのではなく、Javaオブジェクトのエンティティベースでシステムを構築できるのがJPAの大きな利点です(動かせる例題による解説が「わかりやすいJakarta EE」の「17章オブジェクト関係マッピング」にあります)。

 また、SQLの代わりにJPQLというオブジェクトベースの問い合わせ言語も使うことができます。SQLではオブジェクトを扱えませんが、JPQLはオブジェクトを使って複雑な問い合わせを行います(詳細は「18章の問い合わせ言語JPQL」をご覧ください)。なお、「わかりやすいJakarta EE」では、JPQLを直接実行できるJPQL-TESTというプログラムを使って詳しく学習できます。

CDIとかEJBって何?

 Jakarta EEの難点はコトバが難しいところです。でもコトバに惑わされないようにしましょう。実は、とても便利な仕組みが、コトバの裏にかくされているからです。ここでは、コトバを大胆に超訳しつつ解説します。
 

いくつもの王国がある

 CDIは「コンテキストと依存性注入」と訳されていますが、これでは、正直な話、何のことがわかりませんね。EJB(Enterprise JavaBeans)に至っては日本語の訳すらないのでさっぱりです(しかも、Jakarta EE9からはJakarta Enterprise Beansという名前に変わってしまい、そのままではJEBなんですが・・・)。
 そもそも、Jakarta EEはJSF、JPA、CDI、EJBなどの直観的には意味のわからない3文字英語をやたら振り回すので、困ってしまいます。確かに、それぞれが違う王国を築いていて、違うサービスを提供しているのですが、ことばだけからは皆目わかりません。
そこで、これらが何をやってくれるのか、そこに注目して考えてみましょう。
 

EJBはだんだんいらなくなる

 JSFやJPAはこれまで見たように役割がはっきりしています。ひとまずOKですね。
 EJB(Enterprise JavaBeans)は、以前は魔王の館みたいな感じがしていたのですが、いまでは、データベース処理などのビジネスロジックをカンタンに書けるようにしてくれる強い味方です。面倒なことは何もありません。クラスの先頭に@Statelessなどのアノテーションを付けるだけでEJBのクラスになります。
 例えば、データベースではエラー発生時の対応などが必要ですが、EJBはそれを自動的にやってくれるので、書き手は気を使う必要がないという利点があります。ですからJPAを操作するプログラムは、基本的にEJBのクラスを作って作成します。
 そのほかにも、定期的に起動するタイマー処理を仕込むとか、JavaSEではとても苦労したマルチスレッドをアノテーション1つで可能にするとか、シングルトンみたいなデザインパターンが@Singletonというアノテーションだけでできるなど、EJBでなくてはできないようなことがいくつもあります。
 
 ただ、CDIを機能強化して、CDIでEJBを代替できるようにしようというのが、これからの方向性です。すでにデータベース関連はCDIだけで書けるようになりました。その他の機能も、Jakarta EE10以降でCDIで使えるようにすることが提案されています。

ではCDIは?

 実は、先に解説したバッキングビーンがCDIのクラスです。
 @RequestScopedなどをスコープアノテーションといいますが、スコープアノテーションを付けたクラスがCDIのクラスです。他に@SessionScoped(セッション継続の間の寿命)とか、@ApplicationScoped(プログラムが終了するまでの寿命)などがありますが、スコープアノテーションで寿命が決まっていることが大きな特徴です。CDIとは結局、寿命のあるオブジェクトを使えるサービスです。
 
 そして、ほぼすべてのクラス(引数のないコンストラクタを持つなどのとても緩い条件はありますが)をCDIのオブジェクト(CDIビーンといいます)として扱うことができます。今後は、コード作成のベースがCDIビーンになるということですね。

とにかくInjectして使う

 オブジェクトの寿命をCDIシステムが管理する都合から、CDIのクラスはnewで実体化しません。CDIシステムからもらう形をとります。つまり大抵のクラスは、次のようにInjectして生成します

sample.java
@Inject
private SomeObject obj;

 このようなシステムによるオブジェクトの管理と自動配布(もちろん他の言い方もありますが)をDI(依存性注入)といいます。CDIのDIもそれで、Cはコンテキスト、つまりは寿命のことです。ですから、寿命のあるオブジェクトの管理と自動配布がCDIです。

CDIやEJBは難しいことをカンタンにする

 ちょこっとアノテーションを付けるだけで、JavaSEの世界では面倒なことがカンタンに実現できます。
 この仕組みは本当にスバラシイ限りです。
 そこで、CDIとEJBでちょっとだけ例をお話します。

アッという間にコンカレントな処理

 時間のかかる処理を別のスレッドで実行すれば、本来の処理をすぐに続けることができます。例えば、次は電子メールを送信する処理です。EmailSenderというユーティリティクラスのオブジェクトをInjectし、それを使ってメールを送信します。これは、意外と時間がかかる処理ですから、非同期処理にしたいところです。
 JavaSEだと、別スレッドで実行するには、これにRunnableインタフェースを実装した上で、別にスレッドプールを作成して、その中で実行する必要があります。
 しかし、これをEJBのクラスにすれば(遠からずCDIビーンでも可能になります)、アノテーション1つで別スレッドで実行させることができます。
 次を見てください。
 

MailSender.java
@Stateless
public class Mailer{
    @Inject
    EmailSender mail;

    @Asynchronous
    public void sendMail(String to, String subject, String body){
        mail.send(to, subject, body);  
    }

}

 
 先頭行の@Statelessは、このクラスをEJBにするというアノテーションです。このアノテーションをつけるだけで他は何も必要ありません。そして、6行目にある@Asynchronousアノテーションが、別スレッドで実行するためのアノテーションです。コンカレント処理を行わせるには、このアノテーションを付けるだけです。
 これだけでコンカレント処理が実現するなんて、ちょっと驚きですね。
 

オブザーバーパターンがカンタンに実現

 あるオブジェクトが、何かの処理をしたとき、それを他のオブジェクトに教えたいことがあります。例えば、作為的な例ですが、「学生データを学籍簿に登録する」オブジェクトが、「学籍簿から成績簿を作る」オブジェクトや、「学籍簿から学費の納付書を発行する」オブジェクトなどに、登録した事実を伝える場合です。これらを1つのクラスに作っておくのではなく、バラバラにしておけば、自由度が増し、改訂も容易になります(実は、マイクロサービスという最近のトレンドでは、これがサービス同士の連携に利用されます)。このような処理をオブザーバーパターンといいます。
 
 CDIやEJBでは、このオブザーバーパターンをカンタンに作れます。
 次はCDIのクラスでオブザーバーパターンを実装した例です。
 
 例では、上段の学生課(Gakusei_ka)クラスで、学生情報をリストに登録し(ダミーの処理)、その後、イベントを発火して登録した事実をシステム全体に知らせています。
 Eventオブジェクトのfireメソッドがその処理です。引数に登録した学生情報があるので、システムの他のオブジェクトならだれでも、このイベントを捕えることができます。
 

Gakusei_ka.java
@SessionScoped
public class Gakusei_ka implements Serializable {
    @Inject
    private Event<Student> event;   // イベントオブジェクトを用意しておく
    List<Student> ls = new ArrayList<>();
    public void add(Integer number, String name) {
        Student st = new Student(number, name); // 学生データを学籍簿に登録
        ls.add(st);
        event.fire(st);               // 引数(Student型)をセットしてイベントを発火させる
    }
}

 
 次は、イベントを捕える側のクラスです。Studentオブジェクト(@Observesアノテーションを付ける)を引数に持つreceiveメソッドを作っておけば、イベントが投げられた時、リアルタイムにそれを捕えることができます。ここでは、ダミーの処理として、メッセージを出力しています。
 このsoumu_kaクラス以外にも、他のクラスでも同形式のreceiveメソッドを作っておけば、同様にイベントを捕えることができます。
 

Soumu_ka.java
@RequestScoped
public class Soumu_ka {
    public void receive(@Observes Student st) {
        System.out.println("■納付書発行処理:" + st.toString());
    }
}

非同期なオブザーバーパターンも簡単

 オブザーバーがたくさんある場合があります。その場合、いくつものオブザーバーが、順番に同じイベントを受け取っていくので、多い場合は時間がかかります。そこで、event.fire()メソッドをevent.fireAsync()メソッドに変更し、@Observesアノテーションを@ObservesAsyncに書き換えるだけで、なんと、非同期に(それぞれ別スレッドで)実行するようにもできます。簡単ですね(詳細は「13章 CDIの高度な機能」を参照)。

 あっと、それから、ここでは省略しますが、インターセプタというのもあります。作成するのにちょっとだけ手間がかかりますが、既存のクラスのコンストラクタやメソッドに割り込み処理を追加できます。ログを取ったりするような横断的な処理ですね。デバッグなどに、とても重宝します(同じく13章を参照)。
 

これからの主役-RESTfulウェブサービス

 さて、いよいよ、最後の話題。
 これからのサーバーサイドプログラミングでは、RESTfulウェブサービスの比重が次第に大きくなるはずです。RESTfulウェブサービスは、(ホームページをアクセスするように)サーバーの特定のURI(URLとほぼ同じモノ)にアクセスしたとき、何かの処理を実行したり、何かの値を返したりするサービスです。

 HTTPの規則では、サーバーにアクセスする際、ホームページならGETアクセスとみなされますが、RESTfulウェブサービスでは、GET、POST、PUT、DELETEなどのモードを使い分けることができます。このモードとURIの組み合わせ(パラメータも指定できる)で、サーバーに命令を伝えるのがRESTfulウェブサービスです。
 サーバーにアクセスするプログラムは、Java言語ならクライアントAPIというライブラリを使って作成します。ただ、サーバーへの「命令」はHTMLの規則しか使わないので、Java以外の言語でも作成できます。このように言語への依存性がないこともRESTfulウェブサービスの大きな特徴です。

サービスの作成はとても簡単

 作成するには、まずサービス全体に名前を付けます。例えばオンライン書店のサービスならbookshopですね。bookshopサービスには、会員情報の管理や書籍の注文、書籍の発送などについて、具体的なプログラムが必要です。ここで、プログラムする対象は、会員情報、受注情報、発送スケジュールなどですが、これらをリソースといいます。具体的なサーバーサイドのプログラムは、このリソースごとに作ります。いくつかの独立したサービスから構成される、ということです。

 全体を表すサービス名は、Applicationクラスを継承したサブクラスで次のように宣言します。

ServiceConfig.java
@ApplicationPath("bookshop")
public class ServiceConfig extends Application {
}

 な、な、なんと、クラスの中身はいりません。@Applicationアノテーションを付けて、サービス名を書いておくだけです。簡単ですね。

 次に、会員情報リソースに関するサービスを提供するクラスを作ってみましょう。

MemberResource.java
@Path("/member")
public class MemberResource {
    private Member member = new Member(1L, "田中", "tanaka@mail.jp","140-0014", "東京都", "品川区");
    @GET
    public String getMember() {
        return member.toString();
    }
}

 あらすじが分かるように、例では、GETアクセスがあった時の処理だけを定義しています。@GETアノテーションを付けたgetMember()メソッドがそれです。アクセスされると、Memberインスタンスの文字列表現を返します。データベースにアクセスしてもいいのですが、基本はこれだけです。
なお、クラスに付けた@Path("/member")というアノテーションは、サブURIと言って、bookshopサービスの中のメンバー情報サービスであることを示します。したがって、このサービスには、次のURIでアクセスできます。

  http://(サーバーURI)/bookshop/member

 memberのようなサブURIにより、個々のサービスへのアクセスを分けているわけですね。
 (RESTfulウェブサービスは本の20章で詳しく解説しています)

マイクロサービスに向けて

 上の例では、文字列を返していますが、現実にはどんなデータでも返せます。つまり、オブジェクトやJSON、XML、あるいはHTMLなど、何でも返せる(返さない場合もある)ので、それをどう利用するかはクライアント次第です。RESTfulウェブサービスが他のRESTfulウェブサービスにアクセスすることもあります。

 今トレンドになっているマイクロサービスでは、RESTfulウェブサービスで、境界のはっきりした小さなサービスをたくさん立ち上げ、それらを協働させて大きなシステムとして仕上げます。サービスの数は数十から数百になることもあります。しかし、それぞれのサービスが小さく、また、独立しているので、作成や改訂が簡単です。つまり、保守しやすいシステムになるわけです(その分、"協働"が難しくなるのですが)。

 ただ、今までになかった構成法なので、新しい技術が必要です。その体系が、マイクロサービスとして急速に形造られています。やがて、Jakarta EEに取り込まれて、新しい時代のEnterprise Javaができると期待されています。

終わりに

 Jakarta EEの簡単さ、すばらしさが、少しでも伝わったでしょうか?
 Jakarta EEを使うと、実用的なシステムが、比較的簡単に、そして、すばやく構築できます。
 あなたもやってみませんか。

 Javaによるウェブシステムが初めてなら、「わかりやすいJakarta EE」を手に取ってみてください。
 基礎知識だけでなく、実践的なシステム作成技術も解説しています。
 Java言語の初心者でも読めるように書きましたので、きっと役に立つと思います!

 最後におまけの情報です。
 jakarta EEを簡単に使い始められるように、JET(Jakarta EE Toolkit)を作成しました。こちらに解説記事を作成しましたのでご覧ください。解説ビデオも掲載しています。JETをダウンロードして、5分で使い始められるはずです。

 明日の第2日目は、exotic-toyboxさんの「日時APIで期間の判定」です

---------------------------- 
2020.12.01 川場隆
ウェブ: https://k-webs.jp
TW: @tkxlab
e-mail: kawaba[アット]tk-webs.com(@に読み替えてください)

36
28
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
28