SpringフレームBeanの初期化と廃棄---方式:InitializingBeanインターフェース、Dispable Beanインターフェース

14262 ワード

インターフェース
1.InitializingBenインターフェースの概要
SpringにはInitializingBenインターフェースが提供されています.InitializingBeanインターフェースはbeanに属性初期化後の処理方法を提供しています.afterProptiesset方法だけを含みます.このインターフェースのクラスを継承する場合、beanの属性初期化後にこの方法を実行します.InitializingBenインターフェースのソースコードは以下の通りです.
package org.springframework.beans.factory;
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
InitializingBenインターフェースで提供されるafterPropertiesset()方法の名前から推測できる:afterPropertiesset()方法は、属性が与えられた値の後に呼び出される.一体そうですか?afterPropertiesset()方法の呼び出しタイミングを分析します.
2.いつInitializingBeanインターフェースを呼び出しますか?
Spring中のorg.spring frame ewark.beans.factory.support.AbstractAutowireCapable Parble Factory類下のinvoke InitMethods()メソッドに位置し、Springローディングbeanの方法を確認します.
( 本論文は氷河技術チームから転.)  余談:なぜこのinvokeInit Methods()の方法なのかを聞かないでください.もしあなたは私と同じSpringのソースコードに詳しいなら、あなたもこのinvokeInitMethods()の方法だと知っています.ハハ!だから、仲間たちはSpringだけを使わないでください.やはりSpringのソースをたくさん見てください.Springフレームには多くの優れたデザインモデルが使用されており、そのコードの編成規範と厳密さも業界のオープンソースフレームの中では屈指のものであり、非常に読む価値があります.
私たちはAbstract AutowireCable BenFactory類の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に二種類の初期化beanの方式を提供し、InitializingBenインターフェースを実現し、afterPropertiesset方法を実現するか、または構成ファイルと@Ben注釈の中でinit-methodによって指定され、両方の方式が同時に使用できる.InitializingBenインターフェースを実現することは、直接afterPropertiessetを呼び出す方法であり、反射によってinit-methodを呼び出すことによって指定された方法よりも効率が高い.しかしinit-method方式はSpringへの依存を解消した.afterPropertiessetメソッドの呼び出しでエラーが発生した場合は、init-methodで指定された方法を起動しません.すなわちSpringはbeanに対して2つの初期化方式を提供し、最初はInitializingBenインターフェースを実現し、afterPropertiesset方法を実現し、第2の構成ファイルまたは@Ben注解はinit-methodによって指定され、両方の方式が同時に使用でき、同時にafterPropertiessetメソッドを呼び出して、init-method指定の方法を実行する.
 
DispposableBeanインターフェース
1.DispposableBeanインターフェースの概要
org.springframe ewark.beans.factory.Displable Beanインターフェースを実現するbeanは破壊前に、SpringはDisporsable Beanインターフェースのdestroyを呼び出します.まず、DispposableBeanインターフェースのソースコードを見に来ました.
package org.springframework.beans.factory;
public interface DisposableBean {
    void destroy() throws Exception;
}
 
DispposableBeanインターフェースでは一つのdestroy()方法のみが定義されていることがわかる.
ビーンライフサイクルが終わる前にdestoryを呼び出して仕上げ作業をしてもいいです.destory-methodを使ってもいいです.前者はSpringと結合が高く,タイプの強い回転・方法名()を用いて効率が高い.後者は結合が低く,反射を用いて効率が比較的低い.
2.DispposableBeanインターフェースの注意事項
多くの例beanのライフサイクルはSpring容器で管理されていません.ここのDispposable Beanの方法はSpring容器で呼び出されていますので、一つ以上の例が実現されればDispsable Beanは意味がありません.対応する方法は全く呼び出されません.もちろんXMLファイルでdestry方法を指定しても意味がありません.したがって、複数のインスタンスbeanの場合、Springは自動的にベーンの破壊方法を呼び出さない.
シングルインスタンスbean判例
Animalクラスを作成し、InitializingBeanとDispable Beanインターフェースを実現します.コードは以下の通りです.
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

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      。。。。。");
    }
}
 
次に、Animal Config類を新たに作成し、Animalを@Beanで注釈してSpring容器に登録します.
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();
    }
}
 
次に、BenLifeCirculeTestクラスにtestBenLifeCircure 02()方法を追加して試験を行います.以下の通りです.
@Test
public void testBeanLifeCircle02(){
    //  IOC  
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnimalConfig.class);
    System.out.println("IOC      ...");
    //  IOC  
    context.close();
}
 
BenLifeCirculeTestクラスのtestBenLifeCircure 02()を実行する方法で、出力の結果情報は以下の通りです.
   Animal         
   Animal       。。。。。
IOC      ...
   Animal      。。。。。
出力の結果情報から、単一のインスタンスbeanでは、IOC容器の作成が完了したら、自動的にbeanの初期化方法を呼び出します.容器を破壊する前に、自動的にベーンの廃棄方法を呼び出します.
多実例bean判例
多例beanの事例コードは基本的に単一のインスタンスbeanの事例コードと同じですが、Animal Config類においては、Animal()メソッドに@Scope(「prototype」)を追加しました.
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();
    }
}
 
次に、BenLifeCirculeTestクラスにtestBenLifeCircure 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();
}
 
BenLifeCirculeTestクラスのtestBenLifeCircure 03()を実行します.出力の結果情報は以下の通りです.
IOC      ...
-------
   Animal         
   Animal       。。。。。
-------
   Animal         
   Animal       。。。。。
-------
出力の結果情報から、複数のインスタンスbeanでは、Springが自動的にbeanの破壊方法を呼び出さないことが分かる.