Springboot 拡張ポイント BeanDefinitionRegistryPostProcessor

ここに画像の説明を挿入します
Springboot 拡張ポイント シリーズの実装方法と動作原理のコレクション:

Springboot 拡張ポイント ApplicationContextInitializer

Springboot 拡張ポイント BeanFactoryPostProcessor

Springboot 拡張ポイント BeanDefinitionRegistryPostProcessor

Springboot 拡張ポイント BeanPostProcessor

Springboot 拡張ポイント InstantiationAwareBeanPostProcessor

Springboot 拡張ポイント SmartInstantiationAwareBeanPostProcessor

Springboot 拡張ポイント ApplicationContextAwareProcessor

Springboot 拡張ポイント @PostConstruct

Springboot 拡張ポイント InitializingBean

Springboot 拡張ポイント SmartInitializingSingleton

Springboot 拡張ポイント CommandLineRunner および ApplicationRunner

Springboot 拡張ポイント FactoryBean

Springboot 拡張ポイント DisposableBean

Springboot 拡張ポイント シリーズの終わり: Bean のライフサイクル

序文

この記事では、もう 1 つの Springboot 拡張ポイントである BeanDefinitionRegistryPostProcessor について説明したいと思います。このタイプの拡張ポイントは、一般にコンテナ レベルのポストプロセッサと呼ばれます。もう 1 つのタイプは、Bean レベルのポストプロセッサ、コンテナ レベルのポストプロセッサです。ポストプロセッサ。Spring コンテナの初期化後、リフレッシュ前に 1 回実行されます。Bean レベルのリセット プロセッサは、各 Bean がインスタンス化される前後に実行されます。

1. 機能的特徴

  1. postProcessBeanDefinitionRegistry() メソッドは、BeanDefinitionRegistry を通じて BeanDefintion を追加、削除、変更、確認できます。

  2. コンテナレベルの拡張インタフェースである BeanFactoryPostProcessor を継承します。 org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory メソッドは、コンテナがインスタンス化された後、コンテナがリフレッシュされる前に実行されます。つまり、さらにいくつかの変更を加えることができますコンテナがリフレッシュされる前に BeanDefintion に追加されます。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
    
   void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
@FunctionalInterface
public interface BeanFactoryPostProcessor {
    
    
   void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

要約すると、すべての BeanDefinition がロードされた後、Bean が実際にインスタンス化される前に、BeanDefinitionRegistryPostProcessor インターフェースを実装することで、Bean の BeanDefinition プロパティの変更や複雑な Bean の手動登録など、BeanDefinition に対してカスタマイズされた操作を実行できます。

Spring の原則に詳しくない友人は、これを見て少し混乱するかもしれません。BeanDefinitionRegistry とは何ですか? ConfigurableListableBeanFactory とは何ですか? ここで簡単に説明しますので、記事全体の理解がスムーズになります。

1.1 Bean定義

ご存知のとおり、Spring の核の 1 つは IOC (Inversion of Control) です。Spring が Bean 制御の反転を実現できるのは、Spring のコンテナ機能によるものです。Bean が Spring コンテナ管理に含まれる前に、すべての Bean は、 BeanDefinition インスタンスに抽象的にカプセル化されると、Bean は BeanDefinition インスタンス情報に基づいてさまざまな時点でインスタンス化されます。

簡単に言うと、Dog.java は犬などの動物の属性と行動を記述し、BeanDefinition は Dog.java クラスを記述します。

1.2 BeanDefinitionRegistry

BeanDefinitionRegistry は文字通り Bean 定義情報の登録を意味しますが、実際にはこのクラスの機能は文字通り BeanDefinition の管理 (追加、削除、変更、確認) です。

public interface BeanDefinitionRegistry extends AliasRegistry {
    
    
    //注册beanDefinition
   void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
         throws BeanDefinitionStoreException;
    //移除指定的beanDefinition
   void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //根据beanName查询beanDefinition
   BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //判断某个beanDefinition是否已经注册
   boolean containsBeanDefinition(String beanName);
    //获取所有已注册的beanDefinition
   String[] getBeanDefinitionNames();
    //获取所有已注册的beanDefinition的数量
   int getBeanDefinitionCount();
    //判断某个beanDefinition是否已经被使用
   boolean isBeanNameInUse(String beanName);
}

1.3 構成可能なListableBeanFactory

Spring のコンテナについては前述しましたが、Spring のコアの 1 つは IOC であるため、Spring のコンテナ設計はコア中のコアです。Spring のコンテナには多くの形式があります。最も基本的な形式は BeanFactory です。ConfigurableListableBeanFactory は BeanFactory を間接的に継承します。したがって、Spring 基本バージョンのコンテナの機能に加えて、ConfigurableListableBeanFactory 実装クラスにはいくつかの高度な機能もあります。Springboot のデフォルトの実際の実装は DefaultListableBeanFactory です。興味のある友人は、これを入り口として使用してさらに深く掘り下げることができますが、ここでは詳細には触れません。

ここに画像の説明を挿入します

2. カスタム実装

2.1 MyBeanDefinitionRegistryPostProcessor

以下では、特定のクラス MyBeanDefinitionRegistryPostProcessor を使用して BeanDefinitionRegistryPostProcessor インターフェースを実装し、BeanDefinitionRegistryPostProcessor 実装クラスの初期化および実行プロセスを調べます。

postProcessBeanDefinitionRegistry() メソッドが呼び出されると、Dog クラスの BeanDefinition 情報が Spring に手動で登録されます。

postProcessBeanFactory() メソッドが呼び出されると、Spring コンテナから Dog クラスの BeanDefinition 情報と Dog クラスのインスタンスを取得します。

@Data
public class Dog {
    
    
    private String name;
    private String color;
}
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
    
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    
        //手工定义一个beanDefinition实例
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        //给beanDefinition填充属性
        beanDefinition.setBeanClass(Dog.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        PropertyValue propertyValue1 = new PropertyValue("name", "旺财");
        PropertyValue propertyValue2 = new PropertyValue("color", "黑色");
        propertyValues.addPropertyValue(propertyValue1);
        propertyValues.addPropertyValue(propertyValue2);
        beanDefinition.setPropertyValues(propertyValues);
        //注册手工定义的beanDefinition
        registry.registerBeanDefinition("dog", beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        System.out.println("-----------start------------");
        //根据类名取出手工注册的beanDefinition
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dog");
        System.out.println(beanDefinition.getBeanClassName());
        //根据类从容器中取出手工注册的beanDefinition所描述的实例bean
        Dog dog = beanFactory.getBean(Dog.class);
        System.out.println(dog.getName());
        System.out.println(dog.getColor());
        System.out.println("-----------end------------");
    }
}

単体テスト

@Test
public void test(){
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
    Dog dog = ((Dog) context.getBean("dog"));
    System.out.println(dog.getName());
    System.out.println(dog.getColor());
}

2.2 UML クラス図

BeanDefinitionRegistryPostProcessorUML クラス図から、BeanDefinitionRegistryPostProcessor が BeanFactoryPostProcessor を継承し、postProcessBeanDefinitionRegistry() メソッドが BeanDefinitionRegistryPostProcessor に属し、postProcessBeanFactory() が BeanFactoryPostProcessor に属していることがわかります。BeanDefinitionRegistryPostProcessor インターフェースを実装するすべての実装クラスこれら 2 つのメソッドを Springboot の拡張ポイントとして実装する必要があります. の 1 つは、その展開のロジックもこれら 2 つの方法にあります。

ここに画像の説明を挿入します

3. 初期化と実行タイミング

カスタマイズされた MyBeanDefinitionRegistryPostProcessor クラスを通じて、BeanDefinitionRegistryPostProcessor インターフェースが実装されます。プロジェクトの起動から始まる実行プロセスは次のとおりです。

  1. プロジェクトのメインクラスを実行すると、org.springframework.boot.SpringApplication#run が呼び出されます。

  2. boot.SpringApplication#run メソッドに入った後、org.springframework.boot.SpringApplication#refreshContext が実行され、コンテナのリフレッシュが開始され、重要な段階に入るまで、最初に Spring コンテナの初期化のためのいくつかの構成操作があります。

  3. SpringApplication#refreshContext では、実際の更新ロジックは org.springframework.context.support.AbstractApplicationContext#refresh メソッド内にあります。

  4. AbstractApplicationContext#refresh メソッドで org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors を呼び出して、BeanDefinitionRegistryPostProcessor インターフェースを実装する postProcessBeanDefinitionRegistry() および postProcessBeanFactory() の初期化と実行を開始します。

  5. AbstractApplicationContext#invokeBeanFactoryPostProcessors メソッドに入ると、 org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() が再度呼び出されていることがわかりました。

  6. PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() メソッドでは、postProcessBeanDefinitionRegistry() と postProcessBeanFactory() を直接初期化して実行するのではなく、一連の判定を行います。 2. PriorityOrdered インターフェースの実装; 3. Ordered が実装されているかどうか; 4. 残りの他の BeanDefinitionRegistryPostProcessor 実装クラス; カスタマイズされた MyBeanDefinitionRegistryPostProcessor は 4 番目のカテゴリに属する​​ため、すべての実装の中で後で実行されます。前の 3 つの方法を検討できます。

  7. PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() メソッドで MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry メソッドを実行した後、MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory メソッドの実行が開始され、呼び出しプロセス全体から見ると、 postProcessBeanDefinitionRegistry() が postProcessBeanFactory() メソッドより先に実行されます。

以下は、呼び出しプロセス全体に基づいて私が描いたタイミング図です。プロセスは確かに複雑ですが、ロジックは比較的明確なので、理解するのは難しくありません。プロセス全体を本当に理解したい場合は、最良の方法は次のとおりです。この図に従って自分で実行し、もう一度デバッグを通じて各キー ノードの実行プロセスを観察します。
ここに画像の説明を挿入します

4. 内部実装クラス

spring-boot-starter-web の組み込み実装クラスには、CachingMetadataReaderFactoryPostProcessor、ConfigurationClassPostProcessor、ConfigurationWarningsPostProcessor、EmbeddedDataSourceBeanFactoryPostProcessor、ImportsCleanupPostProcessor、TestRestTemplateRegistrar、WebTestClientRegistrar、WsdlDefinitionBeanFactoryPostProcessor が含まれます。各実装クラスを観察してください。同様に、これらの組み込み実装クラスはすべて Springboot BeanDefinitionRegistryPostProcessor の内部クラスは、これらの BeanDefinitionRegistryPostProcessor 内部実装クラスを介して Spring コンテナにいくつかの特別な BeanDefinition を登録します これらの Bean について詳細に展開して話すと、一昼夜話し終えることができなくなりそうです興味のある友人は、ここで詳細を確認できます。これ以上拡張することはできません。

5. まとめ

プロセス全体を整理すると、最も重要なことは実際には 1 つの文です。Spring コンテナが初期化された後、更新される前、つまり、Bean がスキャンされて BeanDefinition として登録された後、正式にインスタンス化される前に、次のことができます。 BeanDefinitionRegistryPostProcessor を実装することで、いくつかの追加操作を実行します。
—————————————
著作権に関する声明: この記事は CSDN ブロガー「Ordinary Trafficker」によるオリジナルの記事であり、CC 4.0 BY-SA 著作権契約に従っています。オリジナルのソース リンクとこのコピーを添付してください。声明を転載するとき。
元のリンク: https://blog.csdn.net/fox9916/article/details/128538625

おすすめ

転載: blog.csdn.net/tian830937/article/details/132947061