Spring-BeanFactory学習(二)

11789 ワード

先週、新しいプロジェクトグループに入り、主に既存のマイクロサービスを最適化し、ログを分類して処理する方法について、サービス間の呼び出しとサードパーティの呼び出しを分離し、それぞれ格納する問題に遭遇しました.しかし、現在のプロジェクトチームの人員はすべて元の開発者ではないため、多くの配置はまだどのように処理するか分からないので、うなずくことがあります.この部分を最適化してから、専門的に記録しましょう.今日も引き続きBeanFactoryのソースコードを学び、前回は主にBeanFactoryの共通メンバー変数とbeanの作成とbeanの初期化の方法を見て、今日は主にbeanの構成とbeanのアセンブリの方法を学びました.

一、自動組立bean


after-instantiationコールバックとbeanプロパティの後置処理を適用して、所与のbeanインスタンスを埋め込むには、コードを参照してください.
@Override
public void autowireBean(Object existingBean) {
    // Use non-singleton bean definition, to avoid registering bean as dependent bean.
    RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
    bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
    bd.allowCaching = ClassUtils.isCacheSafe(bd.getBeanClass(), getBeanClassLoader());
    BeanWrapper bw = new BeanWrapperImpl(existingBean);
    initBeanWrapper(bw);
    populateBean(bd.getBeanClass().getName(), bd, bw);
}

まずRootBeanDefinitionについてお話ししますが、これは重要な概念であり、使用する場所も多いです.RootBeanDefinitionは、実行時にBeanFactory内の特定のbeanをサポートする連結のbean定義を表します.複数の元のbean定義から作成される可能性があります.これらの定義は相互に継承され、通常はGenericBeanDefinitionsとして登録されます.RootBeanDefinitionは本質的に実行時の「統一」bean定義ビューです.RootBeanDefinitionは、spring 2から1つのbean定義を構成フェーズに登録するためにも使用できます.5以降、bean定義をプログラミングで登録するための一般的な方法はGenericBeanDefinitionです.GenericBeanDefinitionの利点は、キャラクタのハードコーディングをルートbeanに定義するのではなく、親依存関係を動的に定義できることです.上のコードは、まずbeanに基づいてRootBeanDefinitionオブジェクトを作成し、その役割ドメインを「prototype」に設定して、beanに依存しないようにします.次に、所与のbeanに基づいてBeanWrapperオブジェクト、すなわちbeanのパッケージオブジェクトを作成します.次に、BeanWrapperオブジェクトを初期化し、最後にpopulateBeanメソッドを実行します.すなわち、指定したBeanWrapperのbeanインスタンス(受信したbeanオブジェクト)に属性値を入力します.populateBeanのコードを見てみましょう.
    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
            else {
                // Skip property population phase for null instance.
                return;
            }
        }

        // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
        // state of the bean before properties are set. This can be used, for example,
        // to support styles of field injection.
        boolean continueWithPropertyPopulation = true;

        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // Add property values based on autowire by name if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // Add property values based on autowire by type if applicable.
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }

        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
        boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

        if (hasInstAwareBpps || needsDepCheck) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

        if (pvs != null) {
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

方法は比較的長く、簡単に見ると、この方法の主な内容は、RootBeanDefinitionのプロパティ値を使用して、所与のBeanWrapperのbeanインスタンスを埋め込むことです.1.まずBeanWrapperがnullであるかどうかを判断し、YesであればRootBeanDefinitionオブジェクトに属性値があるかどうかを判断し、直接異常がある場合はそのままreturnする.2、RootBeanDefinitionオブジェクトが合成されていない場合、合成の意味このbeanはアプリケーション自体で定義されていません.BeanFactoryのh a s I n s I n s t a n tiationAwareBeanPostProcessorsプロパティ値はtrue、すなわちI n s t a n tiationAwareBeanPostProcessorsがあります.BeanFactoryのbeanPostProcessorsコレクションを巡回します.BeanPostProcessorがI n s t a n t i a tionAwareBeanPostProcessorのインスタンスである場合、そのインスタンスのpostProcessAfterInstantiationメソッドが呼び出されます.メソッドがfalseの値を返す場合、変数continueWithPropertyPopulationの値をfalseに設定し、ループを受け入れますが、このメソッドの結果は常にtrueに戻るようです.3、RootBeanDefinitionオブジェクトの属性値を変数pvsに割り当てます.RootBeanDefinitionオブジェクトのアセンブリがタイプ別または名前別にアセンブリされている場合、pvsに基づいてMutablePropertyValuesオブジェクトを作成し、その後のアセンブリタイプはそれぞれ対応するメソッドを呼び出して関連属性値の追加を行い、最後にMutablePropertyValuesオブジェクトをpvsに割り当てます.4.BeanFactoryのh a s I n s t a n t i a tionAwareBeanPostProcessors属性値がtrueまたはRootBeanDefinitionのdependencyCheck属性値がAbstractBeanDefinitionに等しくない場合.DEPENDENCY_CHECK_NONE.filterPropertyDescriptorsForDependencyCheckメソッドを呼び出し、無視された依存インタフェースで定義された無視された依存タイプまたは属性を含まない、指定されたBeanWrapperオブジェクトからPropertyDescriptorsForDependencyCheckメソッドのセットを抽出してフィルタします.BeanFactoryのh a s I n s I n s t a n tiationAwareBeanPostProcessorsプロパティ値がtrueの場合、BeanFactoryのbeanPostProcessorsコレクションを巡回し、BeanPostProcessorがI n s t a n tiationAwareBeanPostProcessorのインスタンスである場合、そのインスタンスのpostProcessPropertyValueメソッドが呼び出されます.つまり、工場がそれらを所与のbeanに適用する前に所与のプロパティ値を後処理し、このメソッドが結果nullを返すと、直接return;RootBeanDefinitionのdependencyCheck属性値がAbstractBeanDefinitionに等しくない場合.DEPENDENCY_CHECK_NONEは、checkDependenciesメソッドを呼び出し、依存性チェックを実行して、関連プロパティが外部に表示されるように設定されていることを決定します.5、変数pvsがnullでない場合、applyPropertyValuesメソッドを実行します.このメソッドは、指定された属性値を適用し、このBeanファクトリ内の他のbeanの実行時参照を解析します.これらのプロパティが永続的に変更されないように、深いコピーを使用する必要があります.AutowireBeanメソッドだけを見ると、それほど多くのコンテンツはないようですが、下を見ると実はたくさんあります.もちろん、これらのコンテンツは私の静的なコード分析に基づいて、プロジェクトを起動してdebugしていません.

二、配置bean


次にconfigureBeanメソッドのコードを見てみましょう.
    public Object configureBean(Object existingBean, String beanName) throws BeansException {
        markBeanAsCreated(beanName);
        BeanDefinition mbd = getMergedBeanDefinition(beanName);
        RootBeanDefinition bd = null;
        if (mbd instanceof RootBeanDefinition) {
            RootBeanDefinition rbd = (RootBeanDefinition) mbd;
            bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
        }
        if (bd == null) {
            bd = new RootBeanDefinition(mbd);
        }
        if (!bd.isPrototype()) {
            bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
            bd.allowCaching = ClassUtils.isCacheSafe(ClassUtils.getUserClass(existingBean), getBeanClassLoader());
        }
        BeanWrapper bw = new BeanWrapperImpl(existingBean);
        initBeanWrapper(bw);
        populateBean(beanName, bd, bw);
        return initializeBean(beanName, existingBean, bd);
    }

この方法は、主に、所与の元のbeanを構成し、bean属性を自動的にアセンブリし、bean属性値を適用し、setBeanNameやsetBeanFactoryなどのファクトリコールバックを適用し、所与の元のbeanをパッケージできるものを含むすべてのbeanバックグラウンドプロセッサを適用する.1.まず、指定されたbean名を作成済みまたは作成直前としてマークします.このメソッドは、BeanFactoryのalreadyCreatedコレクションに現在のbean名があるかどうかを判断し、ない場合は追加し、mergedBeanDefinitionsからbean名を消去します.2、与えられたbean名に基づいてgetMergedBeanDefinitionメソッドを呼び出して「merged」のBeanDefinitionを取得し、変数名はmbdであり、実際にはRootBeanDefinitionインスタンスである.mbdがRootBeanDefinitionインスタンスの場合、mbdは変数rbdに割り当てられ、rdbの役割ドメインがprototypeの場合、rdbは変数bdに割り当てられます.そうしないと、rdbをソースとしてRootBeanDefinitionオブジェクトを再作成し、bdに割り当てられます.3、変数bdがnullの場合、mbdをソースとして新しいRootBeanDefinitionオブジェクトを作成し、bdに値を付与する.bdの役割ドメインが「prototype」でない場合、その役割ドメインを「prototype」に設定し、そのallowCachingの値を設定し、所与のbeanのclassオブジェクトおよびClassLoaderに基づいて判断する.4、BeanWrapperオブジェクトを作成して初期化し、populateBeanメソッドを実行し、プロパティ値を使用して所与のBeanWrapperのbeanインスタンスを埋め込むステップはautowireBeanと同じです.5、initializeBeanメソッドを呼び出し、結果を返します.initializeBeanは前回の学習ですでに話しましたが、ここではこれ以上説明しません.

三、自動組立


この方法を見ているとちょっと変な感じがしますが、autowireとautowireBeanは名前の差が少ないような気がします.AutowireBeanメソッドは、after-instantiationコールバックとbean属性後置処理を適用することによって、所与のbeanインスタンスを埋め込み、実際のbeanインスタンス化後に実行されることを示す.一方、autowireメソッドは、指定されたautowireポリシーを使用して、所与のクラスの新しいbeanインスタンスをインスタンス化します.すなわち、autowireは実際にbeanをインスタンス化し、autowireBeanはbeanの属性を埋め込み、両者には前後関係があります.また、autowireBeanメソッドはvoidであり、autowireはbeanインスタンスを返します.Autowireのコードを見てみましょう.
public Object autowire(Class> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
        // Use non-singleton bean definition, to avoid registering bean as dependent bean.
        final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
            return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance();
        }
        else {
            Object bean;
            final BeanFactory parent = this;
            if (System.getSecurityManager() != null) {
                bean = AccessController.doPrivileged((PrivilegedAction) () ->
                        getInstantiationStrategy().instantiate(bd, null, parent),
                        getAccessControlContext());
            }
            else {
                bean = getInstantiationStrategy().instantiate(bd, null, parent);
            }
            populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
            return bean;
        }
    }

1.まず、指定されたbean classオブジェクト、アセンブリモード、および依存性チェックに基づいて、パラメータとしてRootBeanDefinitionオブジェクトを作成し、その役割ドメインをprototypeに設定します.2、RootBeanDefinitionのgetResolvedAutowireMode値がAUTOWIRE_に等しい場合COSTRUCTORは、コンストラクション関数アセンブリを使用してautowireConstructorメソッドを実行してBeanWrapperインスタンスを取得し、そのインスタンスのgetWrappedInstanceメソッドを呼び出し、そのインスタンスがパッケージされたbeanオブジェクトを返します.この中でautowireConstructorの方法は少し複雑です.3、RootBeanDefinitionのgetResolvedAutowireModeがAUTOWIRE_に等しくない場合COSTRUCTORは、システムのSecurityManagerがnullであるかどうかを判断し、nullであるかどうかを判断し、第4ステップを実行する.nullでなければAccessControllerのdoPrivilegedメソッドを呼び出します.コードにはlambda式が使われていますが、ちょっとわかりません....表示lambdaは爽快と書いてありますが、メンテナンスは面倒です.doPrivilegedメソッドには、主に2つのパラメータがあります.1つはPrivilegedAction、1つはAccessControlContextです.PrivilegedActionは、getInstantiationStrategy()メソッドでbeanインスタンスを作成するInstantiationStrategyインスタンスを取得し、そのinstantiateメソッドを実行してbeanオブジェクトを作成し、getAccessControlContextメソッドでAccessControlContextインスタンスを取得します.4、このステップは、3番目のステップlambda式とほぼ同じであり、ここではオブジェクトインスタンスを直接取得します.5.populateBeanメソッドを実行し、beanを返します.
今日もこれらの方法はAbstractAutowireCapableBeanFactoryクラスに定義されています.またdestroyBeanなどの方法もありますが、次回は勉強を続けましょう.ただ、自分がその原理を理解していないような気がして、コードに従って勉強するしかありません.自分の方法に問題があるかどうか分かりません.