【Java】Spring DIの仕組み

#Spring DIコンテナの機能
* アプリケーションの起動時にエントリポイントが必要
* JavaではMainメソッドが起動するエントリポイントになる
* SpringBootでは**Mainメソッドのクラスに@SpringBootApplicationがついている**
* **Spring ランタイムは起動時にこのアノテーションがついているパッケージ下にある全クラスをチェック**
* **@Bean(及びその派生クラス, @Component, @RestController, @Serviceなど)を 自動的に検出しSpring DIコンテナに登録**
* 検出したメソッドに**@GetMapping**などがついていたらここをエンドポイントとして、”/“のURL(=8080)にリスニング
* そこから来たリクエストをURLの内容に応じて登録したコントローラに自動で分けてくれる
* **Spring Web が選択すると、DIコンテナに登録されたBean から @RestController が付与されたクラスを探して、@GetMapping などが付与されたメソッドをエンドポイントにする**

![DI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/ad07f6f4-5168-6072-ba93-4ca7f31a20df.png)

#ルーティングの仕組みについて
* 以下の例ではDemoApplication、SampleApplicationはBeanとして登録され2つともルーティング対象になる

```
Project Root
└─src
    └─ main
        └─ java  
            └─ com.example
                └─ demo
                    └─DemoApplication
                    └─SampleApplication
```

##失敗例
* DemoApplication、SampleApplication共に”/”を指定した場合、SampleApplicationが優先される。

![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/930d550c-fa12-5584-c25a-12dbaecdea99.png)


```Java:DemoApplicaton.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {

    @RequestMapping("/") //どこのアドレスからとってくるか、”/“はhttp://localhost:8080/を指す
    String index(){
        return "Hello World!";
    }
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
```
```Java:SampleApplicaton.java
package com.example.hoge;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class SampleController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    //URLのrootに対してリクエストが来たら受け取る
    //DemoApplication とルート（=8080）が被っている
    public String index(Model model) {
        model.addAttribute("message", "Hello World!!");
        return "index";
    }
}
```

##ルーティングの仕組み
* **@SpringBootApplicationがcom.example.demo以下にある場合、demoより下のパッケージを読みに行く**
* SampleController.javaをcom.example.hogeに移動→**SampleControllerはルーティング対象外になる！**

```
Project Root
└─src
    └─ main
        └─ java  
            └─ com.example
                └─ demo
                    └─DemoApplication
                └─ hoge
                    └─SampleApplication
```
* “/“を/hogeにしてあげる→パスがhttp://localhost:8080/hoge/ 
* DemoApplication.java が実行 ＞ **Hello World!**
![hellowarld.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/88e1e19a-b030-af75-394a-f4e5fb1622ee.png)

```Java:DemoApplication.java
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {

    @RequestMapping("/hoge")
    String index(){
        return "Hello World!";
    }
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
```

*  SampleControllerの”/”を”/bar”に変更
* http://localhost:8080/bar にアクセス
* **@SpringBootApplicationがパッケージ下にある全クラスをチェックできていない！DIコンテナに登録できていない！**
> **Whitelabel Error Page** 

![err.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/6cd50f89-54f0-0be2-599d-3275d24023e2.png)

```Java:SampleApplicaton.java
package com.example.hoge;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class SampleController {
    @RequestMapping(value = "/bar", method = RequestMethod.GET)
    public String index(Model model) {
        model.addAttribute("message", "Hello World!!");
        return "index";
    }
}
```