SpringBoot のアノテーションについてのメモ

最近勉強を始めたフレームワークなので、お勉強がてら色々書いてみました。
そのうち何かこいつを使って試作してみたいですね。

# DI について

## @Autowired

一部の変数宣言に@Autowired を付与すると、DI の対象クラス（コンポーネントクラス）を探し、その変数にコンポーネントクラスのインスタンスを割り当ててくれます。

以下のクラスが対象です。

- @Component
- @Controller 
- @Service
- @Repository
- @Configuration
- @RestController
- @ControllerAdvice
- @ManagedBean
- @Named
- @Mapper
- @Bean

DI の対象ではないクラス（上記アノテーションが割り当てられていないクラス）のメンバに対して@Autowired を指定すると実行時エラーが出ます。

## @Scope

このアノテーションに引数を指定してクラスに付与すると、そのクラスのライフサイクルを指定することができます。
指定できる引数は以下の通りです。

| スコープ | 概要 |
| --- | --- |
|singleton| Spring 起動時に一つだけインスタンスが生成される。二つ以上は生成されないので、アプリ全体でこの一つのインスタンスが共有される。@Scope を付与しなかった場合はsingleton になる。__singleton のクラスのメンバ変数として、singleton 以外のライフサイクル管理のインスタンス(session等）を持たせてはいけない。Spring 起動中singleton のクラスから参照され続けるため、@Scope 指定したライフサイクル通りに寿命管理されなくなる。__ |
|prototype|対象クラスのインスタンスを取得するタイミングで都度インスタンスが生成される。|
|session|HTTP のセッションが始まってから終わるまでがインスタンスの寿命になる。|
|request|HTTP リクエスト処理を始めてから終わるまでがインスタンスの寿命になる。|
|globalSession|ポートレット環境でのGrobalSession が始まってから終わるまでがインスタンスの寿命になる。|
|application|サーブレットのコンテキストの寿命にインスタンスの寿命が合わせられる。|



```
// サンプルコード
@Controller
@Scope("request")
public class SampleController {

    @Autowired // service にインスタンスが割り当てられる(フィールドインジェンクション)
    private SampleService _service;

    private final SampleComponent _component;
    private SampleComponent _component2;

    @Autowired // コンストラクタインジェンクション。
    public SampleController(SampleComponent component, SampleComponent component2) {
        this._component = component;
        this._component2 = component2;
    }
```





# SpringBoot 起動のためのアノテーション

## @SpringBootApplication
SpringBootのアプリケーションクラスであることを示します。
Spring Initializr あたりを使ってでSpringBoot のプロジェクトを作成すると
デフォルトでSpringBoot の起動用クラスが作られますが、
@SpringBootApplication アノテーションはこの起動用クラスに付与されます。


```
// サンプルコード
@SpringBootApplication
public class SpringBootSampleApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringBootSampleApplication.class, args);
	}
}
```

# コントローラー関連のアノテーション

## @Controller
ブラウザなどからHTTPリクエストを受け付けるクラスに付与します。これを付与したコントローラークラスにはリクエストの受け付け、その後の処理をサービスクラスから呼び出します。
そのため、コントロールクラスはサービスクラスのインスタンスをメンバに持つことが多いです。


リクエストの受け付けには後述する @GetMapping や@PostMapping をメソッドに付与して実現します。

## @RequestMapping

このアノテーションをクラスに付与すると、設定された値は親パスとして機能します。

## @GetMapping
Getリクエストを受け取るためのメソッドに付与します。

## @PostMapping
Postリクエストを受け取るためのメソッドに付与します。

## @Autowired

```
// サンプルコード
@Controller
@RequestMapping("/trial")
public class SampleController {

    @Autowired
    private SampleService service;

    @GetMapping("/sample")
    public String getHello() {
        // sample.html を開く
        return "sample";
    }

    @PostMapping("/hello")
    public String postRequest(@RequestParam("id") String id, Model model) {
        SampleData sample = service.getSample(id);

        // 検索結果をModelに登録し、ブラウザに反映されるようにする。
        model.addAttribute("feedback", sample.getName());

        return "sample/response";
    }
}

```

```
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8"></meta>
  <title>ResponseSample</title>
</head>
<body>
  <!-- コントローラークラスで設定した値はここに反映される -->
  <p th:text="${feedback}"></p>
</body>
</html>```
```

# サービス関連のアノテーション

## @Service

コントローラークラスでリクエストを受け付けた後の処理をサービスクラスで実行します。
このサービスクラスには@Services アノテーションを付与します。
サービスクラスではデータベースへの読み書きは直接行わず、後述するリポジトリクラスを経由してデータ操作を行います。
そのため、サービスクラスはリポジトリクラスのインスタンスをメンバに持つことが多いです。

```
@Service
public class SampleService {

    @Autowired
    private SampleRepository repository;

    /** 従業員を1人取得する */
    public SampleData getSample(String id) {
        // 検索する。実際のDBアクセスはリポジトリクラスに任せる。
        Map<String, Object> map = repository.findById(id);

        // Mapから値を取得し、返却用のSampleDataクラスのインスタンスを構築していく。
        String id = (String) map.get("id");
        SampleData data = new SampleData();
        data.setName(id);

        return data;
    }
}
```

# データ操作関連のアノテーション

## @Repository

DB操作などデータの読み書きをするためのリポジトリクラスに@Repository アノテーションを付与します。
そのため、リポジトリクラスはJdbcTemplate などのDBアクセス用クラスのインスタンスをメンバに持つことが多いです。

```

@Repository
public class SampleRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Map<String, Object> findById(String id) {

        // SELECT文
        String query = "SELECT *"
                + " FROM sample_table"
                + " WHERE id=?";

        // 検索実行
        Map<String, Object> result = jdbcTemplate.queryForMap(query, id);

        return result;
    }
}

```

```

@Data
public class SampleData {
    private String name;
}

```

# Rest実行向けアノテーション

## @RestController

@Controller と同じくコントローラー系のクラスに付与するアノテーションですが、付与されたクラス内のメソッドの戻り値をRESTで受け取ることができるようになります（メソッドの戻り値がHTTPのレスポンスボディとして返される）。


# その他色々参考

- [SpringBootとは？　〜DIについて〜[WIP]](https://qiita.com/sasdos_engee/items/0fed0d4256e6d040fb8b)
- [Spring FrameworkとDIについて](https://blog.mookjp.io/blog-ja/spring-framework%E3%81%A8di%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/)
- [Spring Bootアプリケーションのコードレビューポイント](https://qiita.com/cross-xross/items/144f8bde2ef6fa4b379f)
- [DockerでSpring Boot+CentOS+Apache+MySQLな環境を作る](https://qiita.com/kouryou/items/c62af2804f9ca85f5828)
- [Spring Boot解説第18回(基本編：Controllerとは)](https://qiita.com/TEBASAKI/items/267c261db17f178e33eb)
    - この方の記事が一番勉強になったと思います