【Spring注記駆動開発】InitializingBeanとDisposableBeanを使用してbeanのライフサイクルを管理していることを本当に知っていますか?

8716 ワード

前に書く
『Spring注記駆動開発』で@Bean注記を使用して初期化と破棄の方法を指定する方法は?この記事を見れば十分!!ここでは、@Bean注記を使用してbeanの初期化と破棄を指定する方法について説明します.具体的には、@Bean注記でinit-methodプロパティとdestroy-methodプロパティを使用して初期化方法と破棄方法を指定します.このほか、Springではbeanインスタンスを初期化および破棄する他の方法が提供されていますか?
プロジェクトプロジェクトのソースコードはGitHubに提出されました.https://github.com/sunshinelyz/spring-annotation

InitializingBeanインタフェース
1.InitializingBeanインタフェースの概要
SpringにはInitializingBeanインタフェースがあり、InitializingBeanインタフェースはbeanに属性初期化後の処理方法を提供し、afterPropertiesSetメソッドのみを含み、このインタフェースを継承するクラスはbeanの属性初期化後にこの方法を実行する.InitializingBeanインタフェースのソースコードを以下に示します.
package org.springframework.beans.factory;
public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

InitializingBeanインタフェースで提供されるafterPropertiesSet()メソッドの名前から、afterPropertiesSet()メソッドは、プロパティに値を割り当てた後に呼び出されると推定されます.それはいったいそうなのだろうか.afterPropertiesSet()メソッドの呼び出しタイミングを解析する.
2.InitializingBeanインタフェースはいつ呼び出されますか?
Springのorgにナビゲートします.springframework.beans.factory.support.AbstractAutowireCapableBeanFactoryクラスのinvokeInitMethods()メソッドでは、Springロードbeanのメソッドが表示されます.
余談:なぜこのinvokeInitMethods()メソッドなのか聞かないでください.もしあなたが私と同じようにSpringのソースコードに詳しいなら、あなたもこのinvokeInitMethods()メソッドだと知っています.ハハハハ!だから、皆さんはSpringだけを使うのではなく、Springのソースコードをもっと見てみましょう.Springフレームワークには多くの優れた設計モデルが使用されており、そのコードの作成規範と厳格さも業界のオープンソースフレームワークの中で1、2を数え、非常に読む価値がある.
AbstractAutowireCapableBeanFactoryクラスのinvokeInitMethods()メソッドに来ました.
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
    throws Throwable {
	//   bean        InitializingBean  ,     InitializingBean  ,   bean afterPropertiesSet  
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction) () -> {
                    //  afterPropertiesSet()  
                    ((InitializingBean) bean).afterPropertiesSet();
                    return null;
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            //  afterPropertiesSet()  
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        String initMethodName = mbd.getInitMethodName();
        if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
            //         init-method
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

上記のコードを分析すると、次のような情報が得られます.
  • Springはbeanに2つの初期化beanを提供し、InitializingBeanインタフェースを実現し、afterPropertiesSetメソッドを実現したり、プロファイルと@Bean注釈でinit-methodで指定したりして、2つの方法を同時に使用することができます.
  • インプリメンテーションInitializingBeanインタフェースは、反射呼び出しinit-methodによって指定されたメソッドよりも、afterPropertiesSet()メソッドを直接呼び出す方が効率的です.しかしinit‐method方式はSpringへの依存性を解消した.
  • afterPropertiesSetメソッドを呼び出すときにエラーが発生した場合、init-methodで指定されたメソッドは呼び出されません.

  • すなわちSpringはbeanに2つの初期化方式を提供し,1つ目はInitializingBeanインタフェースを実現し,afterPropertiesSet方法を実現し,2つ目はプロファイルまたは@Bean注記でinit-methodで指定し,2つの方式は同時に使用でき,同時にafterPropertiesSet方法を呼び出した後にinit-methodで指定する方法を実行する.
    DisposableBeanインタフェース
    1.DisposableBeanインタフェースの概要
    実現org.springframework.beans.factory.DisposableBeanインタフェースのbeanが破棄される前にSpringはDisposableBeanインタフェースのdestroy()メソッドを呼び出します.まず、DisposableBeanインタフェースのソースコードを見てみましょう.以下に示します.
    package org.springframework.beans.factory;
    public interface DisposableBean {
    	void destroy() throws Exception;
    }
    

    DisposableBeanインタフェースではdestroy()メソッドが1つしか定義されていないことがわかります.
    Beanライフサイクルが終了する前にdestory()メソッドを呼び出して終了作業を行い、destory-methodを使用することもできます.前者はSpringとの結合が高い、タイプの強転を用いる.メソッド名()で、効率が高い.後者は結合が低く,反射を用い,効率が相対的に低い.
    2.DisposableBeanインタフェースの注意事項
    複数例beanのライフサイクルはSpringコンテナで管理されません.ここでのDisposableBeanのメソッドはSpringコンテナで呼び出されるので、1つの複数例がDisposableBeanを実現しても意味がありません.対応するメソッドは呼び出されません.もちろんXMLプロファイルにdestroyメソッドが指定されても意味がありません.したがって、Springは、マルチインスタンスbeanの場合、beanの破棄方法を自動的に呼び出すことはありません.
    単一インスタンスbeanケース
    次のコードを使用して、Animalクラス実装InitializingBeanとDisposableBeanインタフェースを作成します.
    package io.mykit.spring.plugins.register.bean;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.stereotype.Component;
    /**
     * @author binghe
     * @version 1.0.0
     * @description   InitializingBean   DisposableBean  
     */
    public class Animal implements InitializingBean, DisposableBean {
        public Animal(){
            System.out.println("   Animal         ");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("   Animal       。。。。。");
    
        }
        @Override
        public void destroy() throws Exception {
            System.out.println("   Animal      。。。。。");
    
        }
    }
    

    次に、AnimalConfigクラスを新規作成し、次のようにSpringコンテナにAnimalを@Bean注記で登録します.
    package io.mykit.spring.plugins.register.config;
    
    import io.mykit.spring.plugins.register.bean.Animal;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    /**
     * @author binghe
     * @version 1.0.0
     * @description AnimalConfig
     */
    @Configuration
    @ComponentScan("io.mykit.spring.plugins.register.bean")
    public class AnimalConfig {
        @Bean
        public Animal animal(){
            return new Animal();
        }
    }
    

    次に、次のように、BeanLifeCircleTestクラスにtestBeanLifeCircle 02()メソッドを追加してテストを行います.
    @Test
    public void testBeanLifeCircle02(){
        //  IOC  
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
        System.out.println("IOC      ...");
        //  IOC  
        context.close();
    }
    

    BeanLifeCircleTestクラスのtestBeanLifeCircle 02()メソッドを実行し、出力される結果情報を以下に示します.
       Animal         
       Animal       。。。。。
    IOC      ...
       Animal      。。。。。
    

    出力された結果情報から、単一インスタンスbeanの下でIOCコンテナの作成が完了すると、beanの初期化方法が自動的に呼び出される.コンテナが破棄される前にbeanの破棄方法が自動的に呼び出されます.
    マルチインスタンスbeanケース
    マルチインスタンスbeanのケースコードは基本的に単一インスタンスbeanのケースコードと同じですが、AnimalConfigクラスでは、以下に示すようにanimal()メソッドに@Scope("prototype")注記を追加しました.
    package io.mykit.spring.plugins.register.config;
    import io.mykit.spring.plugins.register.bean.Animal;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    /**
     * @author binghe
     * @version 1.0.0
     * @description AnimalConfig
     */
    @Configuration
    @ComponentScan("io.mykit.spring.plugins.register.bean")
    public class AnimalConfig {
        @Bean
        @Scope("prototype")
        public Animal animal(){
            return new Animal();
        }
    }
    

    次に、次のように、BeanLifeCircleTestクラスにtestBeanLifeCircle 03()メソッドを追加してテストを行います.
    @Test
    public void testBeanLifeCircle03(){
        //  IOC  
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AnimalConfig.class);
        System.out.println("IOC      ...");
        System.out.println("-------");
        //       
        Object bean = ctx.getBean("animal");
        System.out.println("-------");
        //       
        Object bean1 = ctx.getBean("animal");
        System.out.println("-------");
        //  IOC  
        ctx.close();
    }
    

    BeanLifeCircleTestクラスのtestBeanLifeCircle 03()メソッドを実行し、出力される結果情報を以下に示します.
    IOC      ...
    -------
       Animal         
       Animal       。。。。。
    -------
       Animal         
       Animal       。。。。。
    -------
    

    出力された結果情報から、Springは、マルチインスタンスbeanの場合、beanの破棄方法を自動的に呼び出すことはありません.
    さあ、今日はここまで話しましょう.见ることと転送することを忘れないで、もっと多くの人に见せて、一绪に勉强して一绪に进歩します!!
    プロジェクトプロジェクトのソースコードはGitHubに提出されました.https://github.com/sunshinelyz/spring-annotation

    最後に書く
    文章が少し役に立つと思ったら、微信で「氷河技術」の微信公衆番号を検索し、氷河とSpring注釈駆動開発を勉強してください.公衆番号は「spring注釈」のキーワードに返信し、Spring注釈駆動開発の核心知識図を受け取り、Spring注釈駆動開発を迷わないようにする.