春の5.xのソースの旅13 finishBeanFactoryInitializationとgetMergedLocalBeanDefinition
たBeanFactoryの初期化を完了
すでに完成し、分析したようinvokeBeanFactoryPostProcessors
とregisterBeanPostProcessors
した後、コアの一部の途中でスキップ、コアの最後の残りの部分ではない、そこの単一の例でbean
作成は、また、最も中心的な場所、私たちは省略し、ゆっくりとそれを分析します非コアコード、実際には、唯一のコード。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
//准备实例化单例
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
DefaultListableBeanFactory的preInstantiateSingletons
まず第一にあなたが得るだろうbeanDefinitionNames
し、そのコピーを作成し、使用を避けるために時間に変更があります。そして、トラバースbean
それがある場合、名前、非抽象場合、非遅延読み込みのシングルトンインスタンスは、FactoryBean
、それは取得しFactoryBean
ますが、この例に取得する場合、すぐにロードするかどうかを決定し、インスタンスをFactoryBean
インスタンスが作成され、必要なときに、デフォルトでは作成されません作成されました。ここでは、取得するために注意を払う必要がありますFactoryBean
彼らの名前がさbeanName
が先行し&
、それを取得した場合には、シンボルFactoryBean
インスタンスが作成され、名前がありますbeanName
。それがない場合にはFactoryBean
取得に直接行くのタイプ。
買収が完了した後、すべての患者だけでなく、単一のプロセッサのための、それがある場合SmartInitializingSingleton
の行動のタイプafterSingletonsInstantiated
のコールが。
@Override
public void preInstantiateSingletons() throws BeansException {
...
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);//创建一个副本,让原始的还能继续注册bean定义
//触发非懒加载的单例bean初始化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);//合并父类的bean定义
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {//非抽象,单例,非懒加载
if (isFactoryBean(beanName)) {//是否是FactoryBean类型的,是的话要加前缀获取
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);//获取FactoryBean
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;//是否需要立即创建FactoryBean中的bean
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {//非FactoryBean
getBean(beanName);
}
}
}
//所有单例的还要进行处理器处理
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
FactoryBeanの実用的な例
作成FactoryBean
クラスはUserDao
インターフェースである、UserDaoImple
それは実装クラスです。
@Component
public class TestFactoryBean implements FactoryBean<UserDao> {
@Override
public UserDao getObject() throws Exception {
return new UserDaoImple();
}
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
}
テスト- 获取testFactoryBean
取得するには、ある作成されたインスタンス:TestFactoryBean
getObject()
@Test
public void FactoryBeanTest() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(TestFactoryBean.class);
applicationContext.refresh();
Object obj= applicationContext.getBean("testFactoryBean");
System.out.println(obj);
}
テスト2 - 获取&testFactoryBean
取得するTestFactoryBean
自分自身を:
@Test
public void FactoryBeanTest() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(TestFactoryBean.class);
applicationContext.refresh();
Object obj= applicationContext.getBean("&testFactoryBean");
System.out.println(obj);
}
getMergedLocalBeanDefinition合併Bean定義
実際には、これは非常に早い、フロントは今、より適切なを話し、言いませんでした。なぜ、これは持つべきではないbean
、私はこれがためにかもしれないと思うものの定義統一プロセス、多くの場所は、合併後に取得されているbean
ので、対処するために定義されたbean
定義が可能に変更することを扱うとき、最新のを処理したいと、あなたはおそらく変更する必要がありますbean
再び統一に合併後の定義をRootBeanDefinition
。のでBeanDefinition
別の実装クラスがありますが、確かに、より包括的サブクラスがあるだろうRootBeanDefinition
が、彼はまた、コンストラクタとディープコピーのクローニング方法を提供し、あなたは他の渡すことができBeanDefinition
、サブカテゴリーをして、新しい作成RootBeanDefinition
深いの性質にしますコピー。
このメソッドのソースコードを見てみましょうが、見つかった場合、合併買収の定義から始まり、そしてそれ以外の場合は、直接のリターンをマージマージする必要はありません。stale
属性はデフォルトが必要とされ、マージするか否かを示しています。
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null && !mbd.stale) {//存在且不需要合并的话就直接返回
return mbd;
}
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
ときあなたはそれをマージを設定する必要があります
それはときにstale=true
ありません、それは統合の必要性は、私たちはまず、見てみると言うことですAbstractBeanFactory
のclearMergedBeanDefinition
。
彼はそれを使用したところ、中、私たちは統一されているので、ここでのコメントは、彼にそれをマージさせました処理し、その作成するこの時点では、最新のBean定義を取得するには、その一回マージする、最新のBean定義が必要になる場合があり、それを決定するために結合される。別の場所にある最後:そのプロセス終了後、定義はので、変更される可能性があり、私は合併が最新であることを確実にするためにマージする必要があります。AbstractBeanFactory
markBeanAsCreated
invokeBeanFactoryPostProcessors
BeanFactoryPostProcessor
bean
マージの概要
なぜ合併の下に要約されているだけであることを意味spring
しますが、プロセスに必要bean
な定義を統一することができますが、多くのbean
定義が異なるサブクラスの実装クラスであるので、プロセッサを変更することができるspring
、あなたが訪問する必要がbean
定義されたときにマージする1手、最新の合併で、定義は、1缶の中央、実際には、私の推測です。
書き込みも多いので、それは恥ずかしいああ、いくつかの増幅を言うようですが、それは大丈夫だ、あまりにも白私は戻って、我々はそれを継続する次の時間を書いて、うまくはない理解することができます。
さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。