Ratpack入門シリーズ
- Ratpack入門 (1) - Ratpackとは
- Ratpack入門 (2) - アーキテクチャー
- Ratpack入門 (3) - hello world 詳解
- Ratpack入門 (4) - ルーティング & 静的コンテンツ
- Ratpack入門 (5) - Json & Registry
- Ratpack入門 (6) - Promise
- Ratpack入門 (7) - Guice & Spring
- Ratpack入門 (8) - セッション
- Ratpack入門 (9) - Thymeleaf
DIコンテナー
Ratpackは、以前書いたように様々な部品をRegistry
クラスに登録することで、モジュラーなアーキテクチャーを実現しています。これ自体は理想的かつフレキシブルなものであると言えますが、大規模開発にはやはり本格的なDIコンテナーが必要になってくると思います。RatpackはGoogle GuiceまたはSpringのDI機能を、Registry
として使用することができます。
Guice
ratpack.guice.Guice
クラスから、Registry
を作成できます。名前がcom.google.inject.Guice
とかぶっているので注意が必要です。Injector
クラスからRegistry
を作成する例です。
Injector injector = Guice.createInjector( new CustomModule() );
Registry registry = ratpack.guice.Guice.registry( injector );
モジュール作成をRatpack内部のAPIのみから行うこともできます。型がFunction<Registry, Registry>
といびつですが、直接RatpackServerSpec.registry()
に渡すことができます。
Function<Registry, Registry> registry = ratpack.guice.Guice.registry( bindings -> {
bindings.module( CustomModule.class );
} );
モジュールの追加は順番に影響されることに留意する必要があります。後から追加されるモジュールに、内容が上書きされます。
使い方は普通のRegistry
と同様です。Guiceのインジェクターに登録されたクラスを、Registry
のAPIから取得することができます。ハンドラーなどをクラス名で指定すると、コンテナーから取得してくれます。インスタンスの管理はGuiceによって行われているので、普通のGuiceのコードと同じく、依存関係を@Inject
で指定することができます。
public final class CustomHandler implements Handler {
private Database database;
@Inject
public CustomHandler( Database database ) {
this.database = database;
}
@Override
public void handle( Context ctx ) throws Exception {
ctx.render( "CustomHandler: " + database.find() );
}
}
Action<Chain> handlers = chain -> {
chain.all( CustomHandler.class );
};
InjectionHandler
RatpackはGuiceのボイラープレートを減らすため、InjectionHandler
クラスを提供しています。
public static final class CustomInjectionHandler extends InjectionHandler {
public void handle( Context context, Database database ) {
context.render( "CustomInjectionHandler: " + database.find() );
}
}
InjectionHandler
を継承したクラスは、handler
という名前で、第一引数にContext
を持つ関数を一つだけ実装します。Context
に続いて、注入したい依存関係を引数として記述します。
内部的にはハンドラーの呼び出しに対してリフレクションで当該メソッドに処理を委譲する形をとっています。
パフォーマンスやIDEの支援を考えると、個人的にはあまり使用しないほうが良いと思います。
Spring
ratpack.spring.Spring.spring()
メソッドで、SpringのDIコンテナーからRegistry
を作成できます。
Registry registry = Spring.spring( Application.class );
引数に指定するクラスは、@SpringBootApplication
アノテーションのついたクラスです。通常のSpringアプリケーションで使うのと同じで、クラスパスからコンポーネントが検索され、それらのクラスはRegistry
から取得できます。
@Service
public class CustomRenderer implements Handler {
private final CustomRepository repository;
@Autowired
public CustomRenderer( CustomRepository repository ) {
this.repository = repository;
}
@Override
public void handle( Context ctx ) throws Exception {
ctx.render( "Hello from Spring Boot!" );
}
}
@Repository
public static class CustomRepository {
public String find() {
return "This is the mock database.";
}
}
Action<Chain> handlers = chain -> {
chain.all( CustomRenderer.class );
};
まとめ
Javaエコシステムでは、DIコンテナーの使用はほぼ必須と言っていいほどだと思います。Ratpackは特によくつかわれるGuiceとSpringという二つのDIコンテナーに対するサポートを提供しています。また、GuiceはRatpackの各拡張モジュールの統合にも利用されます。
RatpackとGuiceは密接に統合されており、また、DI自体もアプリケーションを疎結合にする強力な手段です。積極的に利用することをお勧めします。