空のライフサイクルコールバックと空のスキャン


基礎課程の金ヨンハンのスプリング講座を聞いて整理した内容ソース

空のライフサイクルコールバック


アプリケーションの開始時(データベース接続プールやネットワークソケットなど)に必要な接続を事前に確立し、アプリケーションの終了時にすべての接続を終了するには、オブジェクトの初期化と終了が必要です.
必要なデータを使用する準備ができているのは、オブジェクトを作成して依存関係を注入した後だけです.したがって、初期化操作は、依存関係注入が完了した後に呼び出さなければならない.
依存関係注入が完了すると、Springは様々な機能を提供し、SpringBinがいつ初期化されるかをコールバック法で通知することができる.また、スプリングはスプリング容器が閉じる前に消灯コールバックを行います.従って、安全にシャットダウン操作を行うことができる.
Springbinのイベントライフサイクルは次のとおりです.
スプリングコンテナの作成->スプリング空席の作成->依存関係の注入->コールバックの初期化->使用->前コールバックのキャンセル->スプリングの終了
コールバックの初期化:空を生成し、空の依存関係注入が完了した後に呼び出す
消滅前コールバック:空が消える前に呼び出す
  • オブジェクトの作成と初期化を分離します.
    作成者は、必要な情報を受信し、メモリを割り当ててオブジェクトを作成します.逆に、初期化は、これらの生成された値を利用して、外部コネクタの接続などの煩雑な操作を実行します.したがって,メンテナンスの観点から,オブジェクトの生成部分と初期化部分を明確に分けることが望ましい.
  • 空のライフサイクルコールバックメソッド


    Springには、空のライフサイクルコールバックをサポートする3つの方法があります.
  • インタフェース(InitializingBeanDisposableBean)
  • public class NetworkClient implements InitializingBean, DisposableBean {
        private String url;
        public NetworkClient() {
            System.out.println("생성자 호출, url = " + url);
        }
        public void setUrl(String url) {
            this.url = url;
        }
        //서비스 시작시 호출
        public void connect() {
            System.out.println("connect: " + url);
        }
        public void call(String message) {
            System.out.println("call: " + url + " message = " + message);
        }
        //서비스 종료시 호출
        public void disConnect() {
            System.out.println("close + " + url);
        }
        @Override
        public void afterPropertiesSet() throws Exception {
            connect();
            call("초기화 연결 메시지");
        }
        @Override
        public void destroy() throws Exception {
            disConnect();
        }
    }
    InitializingBeanは、afterpropertiesSet()メソッドの初期化をサポートします.DisposableBeanは、destroy()の方法で消滅をサポートする.
    この方法は、初期化、消去方法の名前を変更することができず、コードを修復できない外部ライブラリにも適用できないため、あまり使用されません.
  • 空登録初期化,指定消滅方法
  • @Bean(initMethod = "init", destroyMethod = "close")
    上記のコードのように設定情報の初期化・消滅方法を指定できます.
    メソッド名は自由に指定できますが、スプリングコードに依存せず、コードを変更できない外部ライブラリに適用できます.
    さらに、@BeanのdestroyMethodプロパティのデフォルト値は(inferred)であり、この機能はcloseおよびshutdownの名前を持つメソッドを自動的に呼び出す.したがって,Spring Binに直接登録すれば,終了方法は単独で書かなくてもうまく機能する.
  • プレゼンテーション@PostConstruct@preDestory
  •     @PostConstruct
        public void init() {
            connect();
            call("초기화 연결 메세지");
        }
    
        @PreDestroy
        public void close() {
            disconnect();
        }
    これは最新のスプリングで最もお勧めの方法で、注釈を1つ加えるだけで便利です.
    唯一の欠点は、外部ライブラリに適用できないことです.外部ライブラリを初期化および閉じる必要がある場合は、@Beanの機能を使用します.

    くうきょう


    スプリングシートは、スプリングシート容器が終了するまでスプリングシート容器の開始とともに作成される.これは、スプリングシートが基本的に単色調であるためである.スコフとは、空席が存在する可能性のある範囲を指す.
    スプリングは、さまざまなスキャンをサポートします.

  • シングルトーン:基本スキャン、スプリングコンテナの開始と終了を含む最も広いスキャン範囲.

  • プロトタイプ:スプリング容器はプロトタイプ空孔の生成と依存関係の注入にのみ関与し、範囲が短く、管理されない.

  • ネットワークスキャン
    request:Webリクエストの送信と送信の前に保持されるスキャン
    セッション:Webセッションの作成と終了前のスキャン
    アプリケーション:Web上のサーブレットコンテキストと同じ範囲のスキャン
    Websocket:Websocketと同じ範囲のスキャン
  • 空のミラーは次のように指定できます.
    // 컴포넌트 스캔 자동 등록
    @Scope("prototype")
    @Component
    public class HelloBean {}
    
    //수동 등록
    @Scope("prototype")
    @Bean
    PrototypeBean HelloBean() {
     return new HelloBean();
    }

    プロトタイプミラー


    スプリングコンテナでプロトコルタイプのスキャンを問い合わせると、スプリングコンテナは常に新しいインスタンスを生成し、戻ります.
    スプリングコンテナはプロトタイプスペースを生成し、注入依存関係と初期化のみを処理します.空をクライアントに返すと、スプリングコンテナは生成されたプロトコルタイプ空を管理しません.したがって、@PreDestroyのような終了方法は呼び出されない.

    プロトタイプスキャナとモノトーンスキャナを組み合わせて使用するときに発生する問題


    スプリングコンテナにプロトコルタイプミラーの空を要求すると、常に新しいオブジェクトインスタンスが生成され、返されます.ただし、1トン貧と併用する場合は、予想通りにうまく働かないので注意が必要です.

    上図に示すように、モノトーン空間でプロトタイプ空間を使用すると、問題が発生します.
    単トン貧は生成時のみ依存関係注入を受けるため,プロトタイプ貧は単トン貧とともに維持し続ける問題があった.
    ただし、注入ポイントだけで新しいプロトタイプを作成するのではなく、使用するたびに新しいプロトタイプを作成して使用します.

    プロバイダによるトラブルシューティング


    依存関係は外部から注入(DI)を受けるのではなく,依存ロック(DL)と呼ばれる必要な依存関係を直接探す.
    コンテナ内で指定したタイプの空の磁気ディスクライブラリを検索するだけの機能が必要になります.
  • ObjectFactory , ObjectProvider
  • 	@Autowired
    	private ObjectProvider<PrototypeBean> prototypeBeanProvider;
    
        public int logic() {
    		PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
    		prototypeBean.addCount();
    		return prototypeBean.getCount();
    	}
    prototypeBeanProvider.getObject()によって、常に新しいプロトタイプ周波数を生成することが決定される.ObjectProvidergetObject()が呼び出され、内部はスプリングコンテナによって検索され、対応するスペースが返されます.(DL)ObjectFactory:機能が簡単で、スプリングに依存します.ObjectProvider:ObjectFactoryを継承します.オプション、スプレー処理など多くの便利な機能があります.依存スプリング.
  • JSR-330 Provider
  • 	@Autowired
    	private Provider<PrototypeBean> provider;
    
        public int logic() {
    		PrototypeBean prototypeBean = provider.get();
    		prototypeBean.addCount();
    		return prototypeBean.getCount();
    	}
    javax.inject.ProviderというJSR-330 Java規格を使用する方法です.
    使用するには、gradleにjavax.inject:javax.inject:1ライブラリを追加する必要があります.Java規格なので、スプリングではなく他の容器にも使えます.

    ネットワークスキャン


    WebスキャンはWeb環境でのみ実行され、プロトタイプとは異なり、スプリングがスキャンの終了点に管理されるため、終了メソッドが呼び出されます.

    リクエストスキャン



    request scope上の図のように、HTTP requestリクエストごとに割り当てられます.
    複数のHTTPリクエストを同時に受信すると、どのリクエストが残したログを区別するのが難しい場合、request scopeを使用するのが望ましい.
    @Component
    @Scope(value = "request")
    public class MyLogger {
        private String uuid;
        private String requestURL;
    
        public void log(String message) {
            System.out.println("[" + this.uuid + "]" + "[" + this.requestURL + "] " + message);
        }
        
        public void setRequestURL(String requestURL) {
            this.requestURL = requestURL;
        }
    
        @PostConstruct
        public void init() {
            this.uuid = UUID.randomUUID().toString();
            System.out.println("[" + this.uuid + "] request scope bean create: " + this);
        }
    
        @PreDestroy
        public void destroy() {
            System.out.println("[" + this.uuid + "] request scope bean close: " + this);
        }
    }
    @Scope(value = "request")を使用してrequest scopeを指定し、作成時にuuidを自動的に初期化メソッドで作成して保存します.
    各HTTPリクエストはこの空を生成するので、uuidを保存して他のHTTPリクエストと区別することができます.
    @Controller
    @RequiredArgsConstructor
    public class LogDemoController {
        private final LogDemoService logDemoService;
        private final ObjectProvider<MyLogger> myLoggerObjectProvider;
    
        @RequestMapping("log-demo")
        @ResponseBody
        public String logDemo(HttpServletRequest request) {
            MyLogger myLogger = myLoggerObjectProvider.getObject();
            String requestURL = request.getRequestURL().toString();
            myLogger.setRequestURL(requestURL);
    
            myLogger.log("controller test");
            logDemoService.logic("test id");
            return "OK";
        }
    }
    @Service
    @RequiredArgsConstructor
    public class LogDemoService {
        private final ObjectProvider<MyLogger> myLoggerObjectProvider;
    
        public void logic(String id) {
            MyLogger myLogger = myLoggerObjectProvider.getObject();
            myLogger.log("service id = " + id);
        }
    }
    Springアプリケーションを実行すると、モノトーンの空を作成して注入することができますが、リクエストスキャン空はWebリクエストの着信時に生成されるため、MyLogger空のときにProviderを使用してObjectProvider.getObject()を呼び出すまで空の生成を遅延させることができます.

    スコフとエージェント

    @Component
    @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class MyLogger {
    }
    これは,プロバイダを用いずに上記の問題を解決できる方法である.proxyMode = ScopedProxyMode.TARGET_CLASSを追加し、MyLoggerのダミーエージェントクラスを生成し、HTTPリクエストにかかわらず、ダミーエージェントクラスを他の空に予め注入することができる.
    これにより、providerを使用しなくても、依存関係を注入する際に、CGIBというライブラリを介してMyLoggerを継承したダミーエージェントオブジェクトが作成されて注入されます.
    プロキシオブジェクトを使用すると、クライアントは単色で空を調整するようにrequest scopeを簡単に使用できます.ただし動作はモノトーンとは異なるので注意して使いましょう.