[スプリング]単トン容器


次のコードを見てください.
public class SingletonTest {

 @Test
 @DisplayName("스프링 없는 순수한 DI 컨테이너")
 void pureContainer() {
 AppConfig appConfig = new AppConfig();
 //1. 조회: 호출할 때 마다 객체를 생성
 MemberService memberService1 = appConfig.memberService();
 //2. 조회: 호출할 때 마다 객체를 생성
 MemberService memberService2 = appConfig.memberService();
 //참조값이 다른 것을 확인
 System.out.println("memberService1 = " + memberService1);
 System.out.println("memberService2 = " + memberService2);
 //memberService1 != memberService2
 assertThat(memberService1).isNotSameAs(memberService2);
 }
}
  • 私たちが作成したスプリングのない純粋なDIコンテナAppConfigは、リクエストのたびに新しいオブジェクトを作成します.
  • クライアントトラフィックは毎秒100個、毎秒100個のオブジェクトが生成され、消失します.
    ->メモリの浪費が深刻です.
  • ソリューションは、オブジェクトを作成して共有するだけです.
    ->モノトーンパターン
  • モノトーンモード
    これは、
  • クラスインスタンスのみが生成されることを保証する設計モードである.
  • したがって、複数のオブジェクトインスタンスの作成を防止する必要があります.
  • プライベートジェネレータを使用して、外部が新しいキーワードを任意に使用することを阻止する必要があります.
  • モノトーンパターンの適用
    package hello.core.singleton;
    public class SingletonService {
     // 1. static 영역에 객체를 딱 1개만 생성해둔다.
     private static final SingletonService instance = new SingletonService();
     // 2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록
    허용한다.
     public static SingletonService getInstance() {
     return instance;
     }
     // 3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
     private SingletonService() {
     }
     public void logic() {
     System.out.println("싱글톤 객체 로직 호출");
     }
    }
    💁‍♀️本当に設計されたオブジェクトは、コンパイルエラーのみが発生するように設計されています.
    テストしてみる
    @Test
    @DisplayName("싱글톤 패턴을 적용한 객체 사용")
    public void singletonServiceTest() {
     //private으로 생성자를 막아두었다. 컴파일 오류가 발생한다.
     //new SingletonService();
     //1. 조회: 호출할 때 마다 같은 객체를 반환
     SingletonService singletonService1 = SingletonService.getInstance();
     //2. 조회: 호출할 때 마다 같은 객체를 반환
     SingletonService singletonService2 = SingletonService.getInstance();
     //참조값이 같은 것을 확인
     System.out.println("singletonService1 = " + singletonService1);
     System.out.println("singletonService2 = " + singletonService2);
     // singletonService1 == singletonService2
     assertThat(singletonService1).isSameAs(singletonService2);
     singletonService1.logic();
    }
  • privateで新しいキーワードをブロックしました.
  • が呼び出されるたびに、同じオブジェクトインスタンスが返されることが確認されます.
  • モノトーンモードを実現する方法はいろいろあります.ここでは、オブジェクトを事前に作成する最も簡単で、最も安全な方法を選択します.
    しかし驚くべきことに、スプリングコンテナは単調モードを自分で適用します!春万歳😆
    モノトーンモードの問題
  • モノトーンモードを実現するコード自体は多くの必要がある.
  • 依存関係のため、クライアントは特定のクラスに依存します.
    ->DIP違反.
  • クライアントは、OCPの原則に違反する特定のクラスに依存する可能性が高い.
  • をテストするのは難しいです.
  • の内部プロパティを変更または初期化するのは難しいです.
  • プライベートジェネレータでサブクラスを作成するのは難しいです.
  • 結論は柔軟性が悪い.
    ->DIの適用が困難になる.
  • anti-patternとも呼ばれる.
  • たんトンコンテナ

  • スプリングコンテナは、モノトーンモードの問題を解決しながら、オブジェクトインスタンスをモノトーン(1つのみ作成)に管理します.

  • これまで私たちが学んだspringbinは,単色調管理binである.👍

  • スプリングコンテナは、モノトーンモードではなく、オブジェクトインスタンスをモノトーンで管理します.
  • の前に説明したコンテナ作成プロセスについて詳しく説明します.コンテナは管理するオブジェクトを1つだけ生成します.

  • スプリングコンテナは単トンコンテナの役割を果たす.このようなモノトーンオブジェクトを生成および管理する機能をモノトーンレジストリと呼ぶ.

  • スプリングコンテナのこの機能は、オブジェクトを単一の色調に保ちながら、一輪モードのすべての欠点を解決します.
  • モノトーンパターンは、乱雑なコードを追加する必要はありません.
  • は、DIP、OCP、テスト、プライベートジェネレータからモノトーンを自由に使用することができる.
  • テストしてみる
    @Test
    @DisplayName("스프링 컨테이너와 싱글톤")
    void springContainer() {
    
     ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
     
     // 1. 조회: 호출할 때 마다 같은 객체를 반환
     MemberService memberService1 = ac.getBean("memberService",
    MemberService.class);
    
     // 2. 조회: 호출할 때 마다 같은 객체를 반환
     MemberService memberService2 = ac.getBean("memberService",
    MemberService.class);
    
     // memberService1 == memberService2
     assertThat(memberService1).isSameAs(memberService2);
    }
  • スプリングコンテナでは、独自にモノトーンモードを採用!
  • スプリングコンテナを使用すると、お客様が要求するたびに作成するのではなく、作成したオブジェクトを共有することで、これらのオブジェクトを効率的に再利用できます.
  • スプリングのデフォルトの空の登録方式はシングルトーンですが、シングルトーン方式はサポートされていません.リクエストのたびに新しいオブジェクトを作成して返す機能も用意されています.詳細は後述するベンスコフで説明する.
    モノトーンの注意点
  • モノトーンモードでも、スプリングなどのモノクロコンテナでも、オブジェクトインスタンスを1つ共有するオブジェクトインスタンスを作成するモノトーン方式は、複数のクライアントが同じオブジェクトインスタンスを共有するため、モノトーンオブジェクトはステータス設計を維持できません.
    ->無状態に設計する必要があります!
  • 特定のクライアントに依存フィールドはありません.
  • 特定のクライアントは、値を変更できるフィールドを持ってはいけません.
  • は、できるだけ読み取り専用にしてください.
  • フィールドではなくjavaで共有されていない、領域変数、パラメータ、ThreadLocalなどを使用する必要があります.
  • スプリングシートのフィールドに共有値を設定すると、大きな障害が発生する可能性があります!!
  • ThreadaがユーザAコードを呼び出し、ThreadbがユーザBコードを呼び出すとする.
    ユーザーAの注文金額は10000元で、結果は20000元です.
    本当の共有フィールドは気をつけて!スプリングシートを常に無状態に設計しましょう.