Spring フレームワークのライフサイクルとシングルトンの詳細な説明を解き明かす [インタビューの質問と詳細な回答]

目次

I.はじめに

1.1. Spring フレームワークと Bean の概念の紹介

2 番目に、Bean のインスタンス化フェーズ

2.1.Beanのインスタンス化プロセス

2.2. デフォルトのコンストラクターとファクトリーメソッドの使用の導入

3. Beanの初期化フェーズ

3.1. InitializingBean インターフェースと @PostConstruct アノテーションの使用

3.2.Beanの初期化メソッドの構成と実行順序

4番目、Beanの破壊段階

4.1. DisposableBean インターフェースと @PreDestroy アノテーションの使用

4.2.Beanの破棄メソッドの構成と実行順序

5. 面接の質問の説明

5.1.Beanのライフサイクル

結論は:

5.2. Spring の JavaBean はシングルトンですか、それとも複数のインスタンスですか?

口論:

5.3. シングルインスタンス JavaBean とマルチインスタンス JavaBean はいつ作成されますか?

口論:

5.4. シングルトンを使用する場合、JavaBean を初期化しますか?

口論:


I.はじめに

1.1. Spring フレームワークと Bean の概念の紹介

やあ友達!Spring Framework と Bean のストーリーを分析しましょう。

Spring フレームワークは守護聖人のようなもので、Java アプリケーションの管理を引き継ぎます。これはスーパー パーティー オーガナイザーのようなもので、アプリを簡単に管理および制御できます。その目標は、エンタープライズ アプリケーションを構築するための効率的かつ柔軟な方法を提供することです。

それで、ビーンとは何ですか?Bean は、実際には Spring フレームワーク内の実際のオブジェクトです。Bean は、Spring Framework パーティーで楽しんでいる小さな友達だと考えることができます。人間に誕生、成長、就労、退職という段階があるのと同じように、各 Bean には独自のライフサイクルがあります。

まず、Bean のインスタンス化は私たちの誕生のようなもので、Spring は Bean オブジェクトを作成してコンテナにロードする役割を果たします。そして、ビーンの属性付与は、私たちが成長の過程で新たなスキルを習得するのと同じように、様々な属性を注入されてカラフルになっていくのです。

次に、Bean の初期化フェーズです。作業を開始する前に準備する必要があるのと同じように、Bean は、特定の初期化メソッドの呼び出しや、Bean ポストプロセッサーを介した後処理の実行など、いくつかの初期化操作を実行することもできます。

最後に、アプリケーションが Bean を必要としなくなった場合、アプリケーションは、リソースの解放、データベース接続のクローズなど、引退と同じように、いくつかの破棄操作を実行できます。

つまり、Spring フレームワークと Bean はパーティーのようなもので、小さな友達がさまざまな段階で行き来し、喜びと達成感をもたらします。ただし、心配しないでください。Spring Framework は責任あるパーティー主催者であり、すべての Bean が適切に管理され、世話されていることを確認します。

このユーモラスな紹介で Spring フレームワークと Bean についての理解を深めることができれば幸いです。

2 番目に、Bean のインスタンス化フェーズ

2.1.Beanのインスタンス化プロセス

Beanインスタンス化処理とは、定義したBeanを利用可能なオブジェクトインスタンスに変換する処理を指します。Spring フレームワークでは、Bean のインスタンス化は次の段階に分割できます。

  1. Bean 定義のロード: 構成ファイル (XML 構成ファイルなど) またはアノテーションを使用して Bean 定義をコンテナーにロードします。Spring フレームワークが解析を担当します。

  2. Beanのインスタンス化: Beanの定義と構成情報に従って、Beanインスタンスをメモリ上に作成します。これは、コンストラクターのインスタンス化、ファクトリ メソッドのインスタンス化、またはオブジェクトのリフレクションなどを介して実行できます。

  3. 属性の割り当て: 基本データ型、参照型、コレクション型などの属性をインスタンス化された Bean オブジェクトに割り当てます。属性は、注釈または XML 構成ファイルを通じて依存関係に挿入できます。

  4. Aware インターフェースのコールバック: Bean が Aware インターフェースを実装している場合、Spring は自動的に対応するコールバック メソッドを検出して呼び出します。たとえば、ApplicationContextAware インターフェースは ApplicationContext オブジェクトを取得できます。

  5. カスタム初期化メソッド: Bean が初期化メソッド (アノテーションまたは XML 構成ファイルを通じて可能) で構成されている場合、Spring はこのメソッドを呼び出して、Bean がプロパティの割り当てを完了した後にいくつかのカスタム初期化操作を実行します。

  6. ポストプロセッサーのメソッド呼び出し: Bean ポストプロセッサー (BeanPostProcessor) が構成されている場合、Spring は追加の処理操作のためにその関連メソッドを自動的に検出して呼び出します。

  7. Bean の準備が完了しました: 上記の手順の後、Bean のインスタンス化プロセスが完了し、コンテナーで管理および使用できるようになります。

2.2. デフォルトのコンストラクターとファクトリーメソッドの使用の導入

デフォルト コンストラクター: デフォルト コンストラクターは引数のないコンストラクターであり、オブジェクト作成プロセスにパラメーターを渡しません。Spring はデフォルトのコンストラクターを自動的に呼び出して、Bean オブジェクトをインスタンス化します。このメソッドは広く使用されており、他の方法でパラメータを渡さずにオブジェクトを作成するのに便利です。例えば:

public class MyBean {
    // 默认构造函数
    public MyBean() {
        // 初始化操作
    }
}

ファクトリ メソッド: ファクトリ メソッドは、特別なメソッドを通じて Bean オブジェクトをインスタンス化する方法です。通常、このメソッドは専用のファクトリ クラスで定義されます。ファクトリ メソッドを使用すると、Bean オブジェクトをより柔軟に作成でき、パラメータの受け渡しなどの操作をカスタマイズできます。例えば:

public class MyBeanFactory {
    // 工厂方法
    public static MyBean createMyBean() {
        // 创建Bean对象的逻辑
        return new MyBean();
    }
}

サンプル コード: デフォルトのコンストラクターとファクトリ メソッドを使用して Bean オブジェクトをインスタンス化する方法を示します。

public class MyBean {
    private String message;

    // 默认构造函数
    public MyBean() {
        this.message = "Hello, world!";
    }

    // getter和setter方法

    public static MyBean createMyBean() {
        MyBean myBean = new MyBean();
        myBean.setMessage("Hello, Spring!");
        return myBean;
    }
}

3. Beanの初期化フェーズ

3.1. InitializingBean インターフェースと @PostConstruct アノテーションの使用

InitializingBean インターフェイスは次を使用します。

このインターフェースは afterPropertiesSet() メソッドを定義しており、Bean のすべてのプロパティが設定されると、Spring コンテナは自動的にこのメソッドを呼び出して初期化操作を完了します。

import org.springframework.beans.factory.InitializingBean;

public class MyBean implements InitializingBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: Bean is being initialized with message: " + message);
    }
}

@PostConstruct アノテーションの使用

このアノテーションは Bean の初期化メソッドにマークされており、Bean のプロパティが Bean の初期化操作を完了するように設定された後にメソッドが自動的に実行されることを示します。

import javax.annotation.PostConstruct;

public class MyBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct: Bean is being initialized with message: " + message);
    }
}

なお、InitializingBean インタフェースと @PostConstruct アノテーションは同時に使用できますが、これら 2 つのメソッドは必須ではなく、必要に応じてどちらかを選択して Bean を初期化できます。

Spring では、設定ファイルを通じて Bean の初期化メソッドを指定し、XML 設定ファイルの <bean> タグの init-method 属性を使用して設定することもできます。例は次のとおりです。

<bean id="myBean" class="com.example.MyBean" init-method="init">
    <property name="message" value="Hello World" />
</bean>

3.2.Beanの初期化メソッドの構成と実行順序

InitializingBean インターフェース、@PostConstruct アノテーション、または XML 構成ファイルのいずれを使用する場合でも、それらを使用して Bean 初期化メソッドを指定できます。実行順序は同じです。最初に属性の依存関係注入を実行し、次に初期化メソッドを実行します。 。

public class Example {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        MyBean bean = context.getBean(MyBean.class);
        // Bean已经被初始化完成并且可以使用
        
        ((ConfigurableApplicationContext) context).close();
    }
}

上記の例では、ApplicationContext オブジェクトが作成され、XML 構成ファイルがロードされます。getBean() メソッドを呼び出して MyBean のインスタンスを取得すると、Spring コンテナはプロパティの挿入と初期化操作を自動的に実行します。アプリケーションを閉じるときは、((ConfigurableApplicationContext) context).close() メソッドを呼び出してコンテナを閉じることができます。

4番目、Beanの破壊段階

4.1. DisposableBean インターフェースと @PreDestroy アノテーションの使用

DisposableBean インターフェースは以下を使用します。

このインターフェースはメソッド destroy() を定義しており、Bean を破棄する必要がある場合、Spring コンテナは自動的にこのメソッドを呼び出してクリーニング作業を完了します。例は次のとおりです。

import org.springframework.beans.factory.DisposableBean;

public class MyBean implements DisposableBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: Bean is being destroyed with message: " + message);
    }
}

@PreDestroy アノテーションの使用

このアノテーションは Bean の破棄メソッドにマークされており、クリーニング作業を完了するために Bean を破棄する必要があるときにメソッドが自動的に実行されることを示します。例は次のとおりです。

import javax.annotation.PreDestroy;

public class MyBean {
    private String message;
    
    public void setMessage(String message) {
        this.message = message;
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: Bean is being destroyed with message: " + message);
    }
}

Bean の破棄は、設定する XML 構成ファイル内の <bean> タグの destroy-method 属性を使用して、構成ファイルを通じて Bean のメソッドを破棄するように指定することもできます。例は次のとおりです。

<bean id="myBean" class="com.example.MyBean" destroy-method="cleanup">
    <property name="message" value="Goodbye World" />
</bean>

4.2.Beanの破棄メソッドの構成と実行順序

Bean の destroy メソッドが最初に実行され、次にコンテナが閉じられるか破棄されます。

public class Example {
    public static void main(String[] args) {
        // 创建并启动Spring容器
        ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        // 获取Bean实例
        MyBean bean = context.getBean(MyBean.class);
        
        // 使用Bean...
        
        // 手动关闭容器
        context.close();
    }
}

上の例では、ApplicationContext オブジェクトを作成し、XML 構成ファイルをロードしました。getBean() メソッドを呼び出して MyBean のインスタンスを取得すると、Spring コンテナは Bean の破棄メソッドを自動的に実行します。コンテナを手動で閉じるときは、context.close() メソッドを呼び出して Bean の破棄をトリガーできます。

5. 面接の質問の説明

5.1.Beanのライフサイクル

1. XML、Javaアノテーション(アノテーション)、Java Configuration(設定クラス)などを介してSpring Beanをロードします。

2.BeanDefinitionReader: Bean の定義を解析します。Spring コンテナの起動プロセス中に、Bean は Spring 内の BeanDefinition 構造に解析されます。spring.xml の <bean> タグを BeanDefinition 構造に変換することは、XML 解析にある程度似ていることが理解されます。

3.BeanDefinition: 多くのプロパティとメソッドが含まれています。例: id、class (クラス名)、scope、ref (依存 Bean) など。実際には、対応する BeanDefinition の対応する属性に Bean の定義情報 (<bean> など) を格納します。

<bean id="" class=""scope=""> -----> BeanDefinition(id/class/scope)

4.BeanFactoryPostProcessor: Springコンテナ機能の拡張インターフェースです。

知らせ:

1) BeanFactoryPostProcessor が Spring コンテナに BeanDefinition をロードした後、

Bean がインスタンス化される前に実行される

2) Bean メタデータ (BeanDefinition)、つまり BeanDefinition を処理します。

属性の入力、変更、その他の操作

5. BeanFactory: Bean ファクトリー。私たちの要求に応じて必要なさまざまな豆を生産します。

例えば:

BeanFactory -> リスト<BeanDefinition>

BeanDefinition(id/クラス/スコープ/初期化メソッド)

<bean class="com.zking.spring02.biz.BookBizImpl"/>

foreach(BeanDefinition Bean : List<BeanDefinition>){

   //クラス属性の反映メカニズムに従ってオブジェクトをインスタンス化します。

   // 反射割り当て設定プロパティ

}

6. アウェアアウェアインターフェイス: 実際の開発では、Spring コンテナ自体の機能リソースを使用する必要があることがよくあります。

例: BeanNameAware、ApplicationContextAware など。

BeanDefinition は BeanNameAware、ApplicationContextAware を実装します

7.BeanPostProcessor: ポストプロセッサ。Bean オブジェクトがインスタンス化されて注入された後、初期化メソッドの呼び出しの前後にカスタム ロジックを追加します。(AOP の循環通知と同様) 前提条件: Bean オブジェクトが BeanPostProcessor ポストプロセッサを実装していることが検出された場合、Before メソッドと After メソッドが実行されます。

Beanポストプロセッサ

1)前

2) 初期化Beanを呼び出します(InitializingBeanとinit-method、Beanの初期化は完了したとみなされます)

3)その後

8.デストーリー:破壊する

結論は:

1.xml/annotation/configuation JavaBean を設定します。

2. BeanDefinitionReader は、構成された Javabean を解析して BeanDefinition を取得し、最後に List コレクションを取得します。

3. BeanFactoryPostProcessor をトリガーし、JavaBean は初期化前に独自のビジネスを実行します。

4. Spring の beanFactory は、List<BeanDefinition> コレクション (リフレクション インスタンス化) を通じてすべての JavaBean オブジェクトを走査して初期化します。

5. 独自の JavaBean が Spring コンテキストでリソースを動員する必要がある場合は、*Aware 認識インターフェイスを実装する必要があります

6. 独自の JavaBean が初期化されており、拡張する必要がある場合は、BeanPostProcessor を使用してそれを実現する必要があります。

7. 破壊する(破壊する)。

5.2. Spring の JavaBean はシングルトンですか、それとも複数のインスタンスですか?

1. デフォルトは単一インスタンスですが、複数のインスタンスを構成できます。

2. 単一インスタンスの利点はメモリを節約できることですが、欠点は変数汚染があることです (複数インスタンスの利点は変数汚染がないことですが、メモリを非常に消費します)

シングルトン インスタンスとマルチ インスタンスの違いと、それぞれの長所と短所を表す短くて面白い物語です。


ファンタジーな魔法学校に「魔法マン」と呼ばれる特別な教師がいた。彼は超魔法の能力を持っており、生徒たちにあらゆる種類の魔法の呪文を教える責任があります。

マジックマンにとって、彼は完全に単一のケースです。彼は学校全体でこれほど強力な魔法の力を持っている唯一の人物であり、すべての生徒と職員は彼に助けと指導を求めます。彼は常に学校の中心に位置しており、誰もが彼の存在を追い求めている。

しかし、マジックマンの特殊なステータスにより、彼の魔法の力は学校全体に浸透していました。教室でも学校の他の場所でも、彼独特の不思議な雰囲気が溢れています。生徒たちが呪文を唱えようとすると、マジックマンの力の影響を受け、予期せぬ効果が生じることもありました。

対照的に、「複数の雲」と呼ばれる別の教師がいます。彼女はマルチケースで、どのクラスにもいます。彼女は優しく柔軟な魔法の力を持っており、生徒たちのニーズや状況に適応するのが得意です。

ドゥオディユンの指導の下で生徒たちが魔法を唱えるとき、彼女はクラス環境やニーズに応じて生徒たちが最大限の可能性を発揮できるようサポートします。彼女の魔法の力は他のクラスの影響を汚染しないため、生徒たちはより自由に魔法のスキルを探索し開発することができます。

この話は、シングルトンとマルチ インスタンスにはそれぞれ利点と欠点があることを示しています。シングルトンの利点は集中管理と権限にありますが、変動する汚染の問題も発生しやすいです。複数のインスタンスは、さまざまなシナリオに合わせてカスタマイズされたサービスを提供し、変動する汚染という潜在的な問題を回避できます。

ソフトウェアを設計するときは、特定のニーズに応じて適切なモードを選択する必要があります。シングルトンは、グローバルに統合されたアクセスと共有リソースが必要な状況で使用できます。柔軟性が必要で、変動する汚染がないシナリオの場合は、複数のケースを使用することをお勧めします。シングルトンインスタンスとマルチインスタンスの長所と短所のバランスをとり、特定のニーズに基づいて賢明な選択を行う必要があります。

口論:

ParamAction.java

package com.csdn.xw.aop.beanLife;

import java.util.List;

public class ParamAction {
	private int age;
	private String name;
	private List<String> hobby;
	private int num = 1;
	// private UserBiz userBiz = new UserBizImpl1();

	public ParamAction() {
		super();
	}

	public ParamAction(int age, String name, List<String> hobby) {
		super();
		this.age = age;
		this.name = name;
		this.hobby = hobby;
	}

	public void execute() {
		// userBiz.upload();
		// userBiz = new UserBizImpl2();
		System.out.println("this.num=" + this.num++);
		System.out.println(this.name);
		System.out.println(this.age);
		System.out.println(this.hobby);
	}
}

spring-context.xml

  <bean id="paramAction" class="com.csdn.xw.aop.beanLife.ParamAction">
        <constructor-arg name="name" value="三丰"></constructor-arg>
        <constructor-arg name="age" value="21"></constructor-arg>
        <constructor-arg name="hobby">
            <list>
                <value>抽烟</value>
                <value>烫头</value>
                <value>大保健</value>
            </list>
        </constructor-arg>
    </bean>

テストテストクラス

package com.csdn.xw.aop.beanLife;

import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/*
 * spring	bean的生命週期
 * spring	bean的單例多例
 */
public class Demo2 {
	// 体现单例与多例的区别
	@Test
	public void test1() {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
		ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");
		ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");
		// System.out.println(p1==p2);
		p1.execute();
		p2.execute();
		
//		单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;
		applicationContext.close();
	}

	// 体现单例与多例的初始化的时间点 instanceFactory
	@Test
	public void test2() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
	}

	// BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
	// 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
	@Test
	public void test3() {
		// ClassPathXmlApplicationContext applicationContext = new
		// ClassPathXmlApplicationContext("/spring-context.xml");

		Resource resource = new ClassPathResource("/spring-context.xml");
		BeanFactory beanFactory = new XmlBeanFactory(resource);
//		InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
		
	}

}

操作結果:

今回は手動でscope="prototype"のインスタンスを複数設定して見ていきます。

5.3. シングルインスタンス JavaBean とマルチインスタンス JavaBean はいつ作成されますか?

 単一のケース: JavaBean が Spring コンテキストで初期化され、コンテナーのオブジェクトが生成され、コンテナーのオブジェクトが消滅します

 複数の例: JavaBean は使用時に作成され、JVM の実行後に破棄されます。

口論:

インスタンスファクトリー.java

package com.csdn.xw.aop.beanLife;

public class InstanceFactory {
	public void init() {
		System.out.println("初始化方法");
	}

	public void destroy() {
		System.out.println("销毁方法");
	}

	public void service() {
		System.out.println("业务方法");
	}
}

spring-context.xml

  <bean id="instanceFactory" class="com.csdn.xw.aop.beanLife.InstanceFactory"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>

上記の XML 構成には複数のインスタンスがあることがわかります。test2 を呼び出して、「Bean の初期化」が完了したかどうかを確認してみましょう。

Spring のコンテキスト オブジェクトのみを取得し、Bean オブジェクトは取得しないため、存在しないことがわかります。ここで、singletonscope="singleton" に変更して結果を確認します。

 この時点では、Beanオブジェクトの取得の有無に関わらず、JavaBeanが作成されていることが分かりました。

概要: コンテナーの作成後にシングルトンが初期化されるのはなぜですか? シングルトンの考え方は、いつ使用しても作成されることであるため、ブラウザが作成リクエストを送信するのを待つと、ユーザー エクスペリエンスが大幅に低下します。とにかく作成されるだけです。プロジェクトの開始時に作成してみてはいかがでしょうか? そうですね、スタートアップ プロジェクトでは時間がかかります。インスタンスが複数ある場合、100個あれば100個作成するのでしょうか?あなたはそれらを 1,000 個作成しましたが、私が 1,000 個持っていて 1 つしか使用しない場合はどうなりますか? 残りの 999 は無駄になるため、複数のインスタンスは使用するときにのみ作成されます。

5.4.シングルトンを使用する場合、JavaBean を初期化しますか?

BeanFactory は Bean オブジェクトを初期化しますが、実装サブクラスごとに異なる初期化方法が採用されます。デフォルトでは、Bean の初期化はシングルトン モードですぐに実行されますが、このとき XmlBeanFactory がサブクラスとして使用されます。シングルトン モードでのコンテナ作成、Bean依存関係は初期化されず、初期化される Bean オブジェクトを取得するだけです。

口論:

test3 を呼び出して結果を確認します

XmlBeanFactoryのサブクラスとしてシングルトンモードでコンテナが作成されており、Beanの依存関係は初期化されていないので取得して使ってみましょう

 この時点で Bean が作成されます。

私の共有はここで終わりです。議論やコミュニケーションのためにコメントエリアへようこそ!

役に立ったと思ったら、高評価をお願いします♥♥

おすすめ

転載: blog.csdn.net/weixin_74318097/article/details/132358501