コンテナから紐解く本当のSpring入門 #jsug / Understanding Spring Container

コンテナから紐解く本当のSpring入門 #jsug / Understanding Spring Container

2019-08-28
JSUG勉強会で発表した資料です。Springのコア機能であるコンテナ・DI・スコープ・プロキシを解説しています。

5dbaf4015e7f249ab21b195ced8e9e46?s=128

Masatoshi Tada

August 28, 2019
Tweet

Transcript

  1. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナから紐解く 本当のSpring⼊⾨ (株)カサレアル

    多⽥真敏 2019年8⽉28⽇ JSUG勉強会 1
  2. (C) CASAREAL, Inc. All rights reserved. #jsug このセッションについて ▸ Springの基礎となる「コンテナ」「DI」に


    ついて、基礎から分かりやすく解説します ▸ 基本的に初⼼者向けですが、
 Springを利⽤している全ての⽅が対象です 2
  3. (C) CASAREAL, Inc. All rights reserved. #jsug ⾃⼰紹介 ▸ 多⽥真敏(@suke_masa)

    ▸ 研修トレーナー@カサレアル ▸ Spring / Java EE / Microservices
 / Cloud Foundry ▸ Pivotal認定講師 ▸ ⽇本Springユーザ会スタッフ 3
  4. (C) CASAREAL, Inc. All rights reserved. #jsug お願い:⾳にご注意ください! ▸ メモを取る際のキータッチは優しくお願いします。

    ▸ スライドは後ほどWebにアップしますので、
 スライドの写真撮影はなるべくしないでください。 ▸ どうしても撮影されたい場合は、
 Microsoft Pixなど⾳のしないカメラアプリを
 ご利⽤ください。 4
  5. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 5
  6. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 6
  7. (C) CASAREAL, Inc. All rights reserved. #jsug Springの誕⽣ ▸ 2002年、Rod

    Johnson⽒が⾃著の サンプルプログラムとして作成 ▸ 重くて複雑だった当時のJ2EE・EJBに
 対するアンチテーゼだった ▸ Johnson⽒が会社を⽴ち上げたり、
 買収されたり紆余曲折あって、
 現在はPivotal社が中⼼に開発 7
  8. (C) CASAREAL, Inc. All rights reserved. #jsug Springの歴史 8 年

    バージョン できごと 2002 ??? Johnson⽒が本を執筆 2004 Spring 1.x OSS化、XML設定ファイル 2006 Spring 2.x アノテーション対応、MVC誕⽣ 2009 Spring 3.x Java Config、REST対応 2014 Spring 4.x Java 8対応、Spring Boot誕⽣ 2017 Spring 5.x Java 8ベース(9以上も対応)、リアクティブ
  9. (C) CASAREAL, Inc. All rights reserved. #jsug 数々のSpringプロダクト 9 プロダクト

    説明 Spring MVC Webフレームワーク Spring Data データアクセス Spring Security 認証・認可 Spring Batch バッチ処理フレームワーク Spring Boot 設定の簡素化 Spring Cloud マイクロサービス開発
  10. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 10
  11. (C) CASAREAL, Inc. All rights reserved. #jsug Springはコンテナを持っている ▸ コンテナ=インスタンスの⼊れ物

    ▸ Bean=コンテナで管理されたインスタンス 11 コンテナ Bean Bean Bean Bean Bean ※「インスタンス」とは、
  もちろんJavaのインスタンスの
  ことです 必要に応じて
 取り出して使う
  12. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナは全Springプロダクトのベース ▸ 例:Spring

    MVCはDispatcherServlet内に
   コンテナを持っている 12 DispatcherServlet コンテナ Bean Bean Bean 12 必要に応じて
 取り出して使う
  13. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナの機能(詳細は後述) ① Dependency

    Injection ② スコープの管理 ③ プロキシの作成 13
  14. (C) CASAREAL, Inc. All rights reserved. #jsug Beanを定義する⽅法 ① コンポーネントスキャン

    ② Java Config ③ 関数型Bean定義 (今回は割愛) ④ XML (今回は割愛) 14 これらの⽅法は、全て併⽤可能!
  15. (C) CASAREAL, Inc. All rights reserved. #jsug Bean定義⽅法① コンポーネントスキャン ▸

    コンポーネントスキャン
 =指定されたパッケージから@Componentが
  付いたクラスを探す ▸ ⾒つけたらインスタンス化→コンテナに保存 15
  16. (C) CASAREAL, Inc. All rights reserved. #jsug ▸ 右記のアノテーションを
 クラスに付けると、


    @Componentを付けた
 ことと同じになる ▸ クラスの役割に応じて
 変える 16 @Repository @Service @Controller @RestController @Configuration @ControllerAdvice @RestControllerAdvice ɾɾɾ Bean定義⽅法① コンポーネントスキャン ※これらのアノテーションのソースコードを読むと、
  @Componentが付いていることが分かります
  17. (C) CASAREAL, Inc. All rights reserved. #jsug Bean定義⽅法① コンポーネントスキャン 17

    package com.example; @Component public class Hoge { ... } @Configuration @ComponentScan(basePackages = "com.example") public class AppConfig {} ▸ Beanとしたいクラス ▸ 設定クラス (Java Config) @Componentが
 付いたクラスを探す
 パッケージ
  18. (C) CASAREAL, Inc. All rights reserved. #jsug Bean定義⽅法① コンポーネントスキャン ▸

    ίϯϙʔωϯτεΩϟϯ範囲は、basePackagesで
 指定したパッケージのサブパッケージ以下も含む 18 @Configuration @ComponentScan( basePackages = "com.example") public class AppConfig {} com example aaa bbb ccc スキャン範囲
  19. (C) CASAREAL, Inc. All rights reserved. #jsug Bean定義⽅法① コンポーネントスキャン ▸

    basePackagesを指定しなかった場合、
 @ComponentScanが付いたクラスのパッケージ
 がbasePackagesとなる 19 package com.example.config; @Configuration @ComponentScan // basePackages無し public class AppConfig {} これが basePackages になる!
  20. (C) CASAREAL, Inc. All rights reserved. #jsug Bean定義⽅法② Java Config

    ▸ Java Configクラスにメソッドを作成し、
 @Beanを付加する
 → メソッドの戻り値がBeanになる 20 // @ComponentScanは不要 @Configuration public class AppConfig { @Bean public Hoge hoge() { return new Hoge(); } } // @Componentは不要 public class Hoge { ... }
  21. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナを作る・Beanを取得する ▸ Java

    Configクラスを指定して
 ApplicationContext (=コンテナ)を作成 ▸ コンポーネントスキャン・Java Configどちらでも共通 ▸ getBean()でBeanを取得できる 21 // コンテナの作成 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // BeanをDIコンテナから取得(引数は欲しいBeanのデータ型) Hoge hoge = context.getBean(Hoge.class);
  22. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナ作成で⾏われること ▸ コンポーネントスキャンの場合

    1. @Componentが付いたクラスを探す 2. ⾒つけたらインスタンス化 3. コンテナに保存 ▸ Java Configの場合 1. @Beanメソッドを実⾏ 2. 戻り値をコンテナに保存 22 コンテナ作成は
 重い処理なので、
 1度コンテナを
 作成したら
 それを使い回す! ※࣮ࡍʹ͸ɺΠϯελϯεੜ੒ͷλΠϛϯά͸
 ɹείʔϓʢޙड़ʣʹΑͬͯҟͳΓ·͢ɻ
 ɹ͜͜Ͱઆ໌͍ͯ͠Δͷ͸singletonείʔϓͷ৔߹Ͱ͢
  23. (C) CASAREAL, Inc. All rights reserved. #jsug Spring Bootの場合 23

    package com.example; @SpringBootApplication public class MyApplication { public static void main(String[] args) { // コンテナの作成 ApplicationContext context = SpringApplication.run(MyApplication.class); } } これがbasePackages @Configuration @ComponentScan @EnableAutoConfiguration を組み合わせたアノテーション ※@EnableAutoConfigurationについては下記資料を参照
  https://www.slideshare.net/masatoshitada7/spring-boot-jjug
  24. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナのまとめ ▸ コンテナ=インスタンス(Bean)の⼊れ物

    ▸ コンポーネントスキャン ▸ @ComponentでBeanにするクラスを指定、 @ComponentScanで探す範囲を指定 ▸ Java Config ▸ @Beanを付加したメソッドの戻り値がBeanになる 24
  25. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 25
  26. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナの機能(再掲) ① Dependency

    Injection ② スコープの管理 ③ プロキシの作成 26
  27. (C) CASAREAL, Inc. All rights reserved. #jsug Dependency Injectionとは ▸

    ⽇本語で⾔うと 27 依存性の注⼊
  28. (C) CASAREAL, Inc. All rights reserved. #jsug 28

  29. (C) CASAREAL, Inc. All rights reserved. #jsug Dependency Injectionとは 29

    依存性の注⼊ 必要なインスタンス (⾃動的)代⼊
  30. (C) CASAREAL, Inc. All rights reserved. #jsug newしないで代⼊してもらう=DI 30 objA

    objB objA objB 代⼊ new ⭕ ❌ ▸ DIは、Bean⽣成時にコンテナが⾏う ▸ newしないことで、単体テストなどの時に
 インスタンスの差し替えが可能
  31. (C) CASAREAL, Inc. All rights reserved. #jsug アノテーション+コンポーネントスキャンの場合 ▸ コンストラクタに@Autowiredを付加し、


    引数に欲しいBeanを指定 ▸ コンテナが適切なBeanを引数に代⼊してくれる 31 @Component public class Hoge { private final Fuga fuga; @Autowired public Hoge(Fuga fuga) { this.fuga = fuga; } } コンテナ Hoge Fuga DI DI ※クラス内にコンストラクタが1つのみの場合、
  @Autowiredは省略可能
  32. (C) CASAREAL, Inc. All rights reserved. #jsug Java Configの場合 ▸

    @Beanメソッドの引数に欲しいBeanを指定し、
 メソッド内に代⼊するコードを記述 ▸ コンテナが適切なBeanを引数に代⼊してくれる 32 @Configuration public class AppConfig { @Bean public Hoge hoge(Fuga fuga) { return new Hoge(fuga); } } コンテナ Hoge Fuga DI DI
  33. (C) CASAREAL, Inc. All rights reserved. #jsug いろんなDI ▸ コンストラクタインジェクション

    33 @Component public class Hoge { private final Fuga fuga; @Autowired public Hoge(Fuga fuga) { this.fuga = fuga; } } @Component public class Hoge { private Fuga fuga; @Autowired public setFuga(Fuga fuga) { this.fuga = fuga; } } @Component public class Hoge { @Autowired Fuga fuga; } ▸ setterインジェクション ▸ フィールドインジェクション 唯⼀Hogeを変更不能に できるので コンストラクタ インジェクション推奨 ※メソッドインジェクションとも呼びます ※変更不能(イミュータブル)=フィールドの値を書換不可能
  34. (C) CASAREAL, Inc. All rights reserved. #jsug DIのまとめ ▸ DI=必要なインスタンスの代⼊

    ▸ DIはコンテナがBeanを⽣成する際に⾏う ▸ コンストラクタにҾ਺Λ෇͚ͯ@Autowired
 or @Beanメソッドに引数 でBeanを代⼊可能 ▸ コンストラクタインジェクションが推奨 34
  35. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 35
  36. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナの機能(再掲) ① Dependency

    Injection ② スコープの管理 ③ プロキシの作成 36
  37. (C) CASAREAL, Inc. All rights reserved. #jsug スコープとは ▸ コンテナが管理している、Beanの有効範囲

    ▸ Beanがいつ⽣成され、いつ破棄されるか 37 スコープの種類 説明 singleton インスタンスは1つのみ(デフォルト) prototype 必要な時にインスタンスが毎回作られる request リクエストと同じ session セッションと同じ
  38. (C) CASAREAL, Inc. All rights reserved. #jsug デフォルトはsingleton ▸ 1つのインスタンスが


    各所で使い回される ▸ フィールドで値を
 保持するのは厳禁!! ▸ セキュリティ事故に… 38 Bean 値 A B 値を
 保存 値が
 ⾒える
  39. (C) CASAREAL, Inc. All rights reserved. #jsug スコープの考え⽅ ▸ ほとんどのBeanはsingletonでOK

    ▸ それ以外にしたくなったら、まず設計を⾒直す ▸ たまにsession使うかな・・・?くらい。 39
  40. (C) CASAREAL, Inc. All rights reserved. #jsug スコープの指定⽅法① ▸ @Scope("スコープ名")をBeanに付加

    40 @Scope("session") @Component public class Hoge { ... } @Configuration public class AppConfig { @Scope("request") @Bean public Hoge hoge() { ... } }
  41. (C) CASAREAL, Inc. All rights reserved. #jsug スコープの指定⽅法② ▸ @RequestScope・@SessionScopeも⽤意されている

    41 @SessionScope @Component public class Hoge { ... } @Configuration public class AppConfig { @RequestScope @Bean public Hoge hoge() { ... } }
  42. (C) CASAREAL, Inc. All rights reserved. #jsug スコープのまとめ ▸ singleton・prototype・request・sessionの


    4種類 ▸ デフォルトはsingleton。値の保持厳禁! ▸ @Scopeで指定 42
  43. (C) CASAREAL, Inc. All rights reserved. #jsug ⽬次 ① Springの歴史

    ② Springのコンテナとは ③ Dependency Injectionとは ④ スコープとは ⑤ プロキシとは 43
  44. (C) CASAREAL, Inc. All rights reserved. #jsug コンテナの機能(再掲) ① Dependency

    Injection ② スコープの管理 ③ プロキシの作成 44
  45. (C) CASAREAL, Inc. All rights reserved. #jsug プロキシ プロキシとは ▸

    本来のBeanを
 ラップしたインスタンス ▸ インタフェースまたは
 継承を利⽤して作られる ▸ 他のBeanには
 プロキシがDIされる 45 <<interface>> Hoge HogeImpl (Bean) ※インタフェースの場合はJDK Proxy、
  継承の場合はCGLibを利⽤してプロキシが作られます
  46. (C) CASAREAL, Inc. All rights reserved. #jsug プロキシの⽬的① AOP ▸

    本来の処理の前後に、割り込み処理を⾏う ▸ トランザクションの開始・終了、権限チェックなど 46 ※AOP : Aspect Oriented Programming // イメージコード public class HogeProxy implements Hoge { public void doSomething() { // 本来のBean Hoge hoge = ...; // 前処理の割り込み interceptor.doBefore(); // 本来の処理 hoge.doSomething(); // 後処理の割り込み interceptor.doAfter(); } }
  47. (C) CASAREAL, Inc. All rights reserved. #jsug @Scope("singleton") @Component public

    class SingletonScopeBeanImpl implements SingletonScopeBean { private final RequestScopeBean rsb; @Autowired public SingletonScopeBean(RequestScopeBean rsb) { this.rsb = rsb; } public void doSomething() { rsb.execute(); } } プロキシの⽬的② スコープの違いを吸収 47 こちらもsingletonに なってしまう?
 → DIされるのは プロキシなので…
  48. (C) CASAREAL, Inc. All rights reserved. #jsug // イメージコード public

    class RequestScopeBeanProxy implements RequestScopeBean { ApplicationContext context; @Override public void execute() { // 本来のBeanを毎回コンテナから取得している RequestScopeBean rsb = context.getBean(RequestScopeBean.class); rsb.execute(); } } プロキシの⽬的② スコープの違いを吸収 48 本来のBeanは 直接DIされないので、 スコープが違っていても ⼤丈夫! ※このプロキシはインタフェースで作成していますが、
  継承の場合でも同様です
  49. (C) CASAREAL, Inc. All rights reserved. #jsug 誰がプロキシを作っているか ▸ BeanPostProcessorがプロキシを作っている

    ▸ コンテナがBeanインスタンスを⽣成した直後に実⾏ 49 HogeImpl (Bean) BeanPost Processor プロキシ HogeImpl (Bean)
  50. (C) CASAREAL, Inc. All rights reserved. #jsug どのBeanにプロキシが作られるか ① AOPを利⽤しているBean

    ▸ @Transactional、@PreAuthorize、@Cachable、 @Retryableなど ② @ScopeでproxyMode = TARGET_CLASS
 またはINTERFACESが指定されているBean ▸ @RequestScopeや@SessionScopeは、
 デフォルトでTARGET_CLASSが指定されている 50
  51. (C) CASAREAL, Inc. All rights reserved. #jsug プロキシのまとめ ▸ プロキシ=本来のBeanをラップしたインスタンス

    ▸ インタフェースまたは継承を利⽤して作られる ▸ AOPでの割り込み処理を実現する ▸ スコープの違いを吸収できる 51
  52. (C) CASAREAL, Inc. All rights reserved. #jsug 本⽇のまとめ ▸ SpringはコンテナでBeanを管理している

    ▸ DIは必要なBeanの⾃動的代⼊ ▸ スコープは4種類。デフォルトはsingleton ▸ プロキシによって、割り込み処理と、
 スコープの違いの吸収が可能になる 52
  53. (C) CASAREAL, Inc. All rights reserved. #jsug おすすめ市販書籍 ▸ 上記以外は、内容がやや古かったりするので


    個⼈的にはおすすめしません 53
  54. (C) CASAREAL, Inc. All rights reserved. #jsug ご清聴ありがとうございました! 54