概要
Agile 開発でプロダクト開発していると、最初の方はある程度仕様が固まっているので、大きく仕様変更することはなく、ソースコードを削除するなんてことはあまり起きないですが、開発が進んでいくと、突然の仕様変更が必要になることってありますよね。せっかく、今まで作ってきたコードが全く意味をなさなくなることも多々あります。
でも、ユーザーがそう求めるなら仕方ない… せっかくきれいに書いてきたクラスを全部修正しよう…
と、思うのですが、Inject しているクラスが変更されるだけであれば、Inject するものを新たに作成してそちらを Inject すればいいんじゃないの???
そうすれば、やっぱり前の仕様のほうが良かった!ってなっても、Inject するクラスを前のものに戻すだけで一切手間がかからない!(結合テストは修正しないといけないかも)
ということで、今回は Quarkus では Inject するクラスを変える場合どうしたらいいか紹介していきます!
Book API のアーキテクチャの説明
まず、Book API の構造を見ていきます。
単純な三層構造で凹型アーキテクチャを採用しています。
![画像に alt 属性が指定されていません。ファイル名: e382ade383a3e38395e3829ae38381e383a3.png](https://ryoskblog.files.wordpress.com/2021/02/e382ade383a3e38395e3829ae38381e383a3.png?w=672)
![画像に alt 属性が指定されていません。ファイル名: e382ade383a3e38395e3829ae38381e383a3.png](https://ryoskblog.files.wordpress.com/2021/02/e382ade383a3e38395e3829ae38381e383a3.png?w=672)
![画像に alt 属性が指定されていません。ファイル名: e382ade383a3e38395e3829ae38381e383a3.png](https://ryoskblog.files.wordpress.com/2021/02/e382ade383a3e38395e3829ae38381e383a3.png?w=672)
今回は、データベースへのアクセス方法がもともと EntityManager を使っていたところ Panache に変えようという想定で実装を変えていきます。( Panache に関しては以前の記事で紹介したので見てください)
Panache を使うということは Repository が不要になり、Service で直接 Panacheが提供するメソッドでデータベースアクセスを行います。
なので、Service に内の実装が大幅に変わることが想定されます。
よって、Controller が Inject している Service を切り替える必要があります!
Book API を使って Inject するクラスを変更
以下のプログラムを見てください。
@ApplicationScoped
@Path("/book")
public class BookController {
@Inject
BookService bookService;
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public BookResponse getBook(@PathParam("id") String bookId) {
Book book = bookService.getBook(Integer.valueOf(bookId));
return BookResponse.of(book);
}
}
まず、BookController のクラスが BookService を Inject しています。
この BookService を実装しているクラスが一つだと問題なくコンパイルできるのですが、新しく別の実装をしているクラスを作成すると、Interface を実装しているクラスが2つになり、コンパイラがどちらを Inject していいかわからなくてエラーになってしまいます!
そこで、Service を実装クラスは以下のようにします。
@ApplicationScoped
@Alternative
@Priority(1)
public class BookServiceImpl implements BookServie {
@Inject
BookRepository bookRepository;
@Override
public Book getBook(Integer bookId) {
System.out.println("not panache");
return bookRepository.getBook(bookId);
}
}
クラスに @Priority(1) というアノテーションがついているのがわかると思います。このアノテーションをもう一方のクラスにもつけて、 @Priority(2) とすることで、Inject する優先順位をつけることができます!
@ApplicationScoped
@Alternative
@Priority(2)
public class BookServiceImpl implements BookServie {
@Inject
BookRepository bookRepository;
@Override
public Book getBook(Integer bookId) {
System.out.println("panache");
return bookRepository.getBook(bookId);
}
}
数字が低いほど優先順位が高いので、いきなり1という数字をつけるのではなく10くらいにしておくと今後の実装に便利になりそうですね。
この状態で、quarkus を実行してアクセスしてみましょう。
すると、標準出力で “not panache” と出てくると思います。@Priorityの数値を入れ替えると、”panache”と出力されることも確認できると思います。
これで、Injectするクラスを自由に変えることに成功しました!せっかく作ってクラスもそのまま取っておけますね!
まとめ
@ApplicationScopedに指定されたクラスの実装が開発途中で仕様を変えなければならなくなってしまった時、既存のクラスを削除するのはもったいないし、一旦後で戻って来れるようにしておきたい時ありますよね….
そんな時は、そのクラスに@Priorityをつけて、新しくクラスを作ってそちらに優先度が高い@Priorityをつけることで解決できることが今回わかりました!
使わないクラス本来消すべきですが、まだ検証段階とかだと本当に消していいのかなと思ってしまうこともあるので、一時的に Inject するクラスを変更できるとかなり便利だと思うので、ぜひ活用してみてください!
コメント