Ratpack入門 (7) - Guice & Spring

## Ratpack入門シリーズ

1. [Ratpack入門 (1) - Ratpackとは](https://qiita.com/minebreaker/items/d7eeca815872a97069f5)
2. [Ratpack入門 (2) - アーキテクチャー](https://qiita.com/minebreaker/items/a9b256fd8a1513104669)
3. [Ratpack入門 (3) - hello world 詳解](https://qiita.com/minebreaker/items/b26d7d0677f91f17a7b5)
4. [Ratpack入門 (4) - ルーティング & 静的コンテンツ](https://qiita.com/minebreaker/items/8f26d8350f936ad669c2)
5. [Ratpack入門 (5) - Json & Registry](https://qiita.com/minebreaker/items/4353611cc541e3cb35fb)
6. [Ratpack入門 (6) - Promise](https://qiita.com/minebreaker/items/4689058d0d7b34d99c74)
7. [Ratpack入門 (7) - Guice & Spring](https://qiita.com/minebreaker/items/52b303bc18db5b33bd68)
8. [Ratpack入門 (8) - セッション](https://qiita.com/minebreaker/items/1ebaa492b257365e1e5e)
9. [Ratpack入門 (9) - Thymeleaf](https://qiita.com/minebreaker/items/50693a4d6614979f654c)


## DIコンテナー

Ratpackは、[以前書いたように](https://qiita.com/minebreaker/items/4353611cc541e3cb35fb#registry%E3%81%A8rendererparser%E3%81%AE%E9%96%A2%E4%BF%82)様々な部品を`Registry`クラスに登録することで、モジュラーなアーキテクチャーを実現しています。これ自体は理想的かつフレキシブルなものであると言えますが、大規模開発にはやはり本格的なDIコンテナーが必要になってくると思います。Ratpackは[Google Guice](https://github.com/google/guice)または[Spring](https://spring.io/)のDI機能を、`Registry`として使用することができます。


## Guice

`ratpack.guice.Guice`クラスから、`Registry`を作成できます。名前が`com.google.inject.Guice`とかぶっているので注意が必要です。`Injector`クラスから`Registry`を作成する例です。

```java
Injector injector = Guice.createInjector( new CustomModule() );
Registry registry = ratpack.guice.Guice.registry( injector );
```

モジュール作成をRatpack内部のAPIのみから行うこともできます。型が`Function<Registry, Registry>`といびつですが、直接`RatpackServerSpec.registry()`に渡すことができます。

```java
Function<Registry, Registry> registry = ratpack.guice.Guice.registry( bindings -> {
    bindings.module( CustomModule.class );
} );
```

モジュールの追加は順番に影響されることに留意する必要があります。後から追加されるモジュールに、内容が上書きされます。

使い方は普通の`Registry`と同様です。Guiceのインジェクターに登録されたクラスを、`Registry`のAPIから取得することができます。ハンドラーなどをクラス名で指定すると、コンテナーから取得してくれます。インスタンスの管理はGuiceによって行われているので、普通のGuiceのコードと同じく、依存関係を`@Inject`で指定することができます。

```java
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() );
    }
}
```

```java
Action<Chain> handlers = chain -> {
    chain.all( CustomHandler.class );
};
```

### `InjectionHandler`

RatpackはGuiceのボイラープレートを減らすため、`InjectionHandler`クラスを提供しています。

```java
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`を作成できます。

```java
Registry registry = Spring.spring( Application.class );
```

引数に指定するクラスは、`@SpringBootApplication`アノテーションのついたクラスです。通常のSpringアプリケーションで使うのと同じで、クラスパスからコンポーネントが検索され、それらのクラスは`Registry`から取得できます。

```java
@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!" );
    }
}
```

```java
@Repository
public static class CustomRepository {
    public String find() {
        return "This is the mock database.";
    }
}
```

```java
Action<Chain> handlers = chain -> {
    chain.all( CustomRenderer.class );
};
```

## まとめ

Javaエコシステムでは、DIコンテナーの使用はほぼ必須と言っていいほどだと思います。Ratpackは特によくつかわれるGuiceとSpringという二つのDIコンテナーに対するサポートを提供しています。また、GuiceはRatpackの各拡張モジュールの統合にも利用されます。

RatpackとGuiceは密接に統合されており、また、DI自体もアプリケーションを疎結合にする強力な手段です。積極的に利用することをお勧めします。