3詳細な春の5.xソースの旅17 getBean

doCreateBean

プロセッサの前の部分には、オブジェクトが存在しない場合、あなたはなるでしょう、オブジェクトをインスタンス化するために返すことがdoCreateBean真のオブジェクトを作成します。この方法は非常に複雑で、私たちはゆっくりと実行されます。まず、キャッシュが最初にあなたがある1つのインスタンスを作成するために取得していない場合は、取得するBeanWrapperパッケージの種類を、プロセッサapplyMergedBeanDefinitionPostProcessors循環参照を解決するために、必要に応じて、シングルトンの工場に追加されます、そして満たされた財産、初期化返す前に破壊コールバックを登録。各プロセスの途中に非常に複雑であり、我々はゆっくりと言います。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {


		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {//获取factoryBean实例缓存
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {//没有即创建实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();//获取原始bean
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {//不为空的bean
			mbd.resolvedTargetType = beanType;
		}
		//处理器修改合并bean定义
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					...
				}
				mbd.postProcessed = true;
			}
		}
		//暴露早期的单例,处理循环引用
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			...
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));//添加一个单例工厂方法
		}
		//进行初始化
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			...
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException...
					}
				}
			}
		}

		// Register bean as disposable.
		try {//注册可销毁的bean
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			...
		}

		return exposedObject;
	}

Beanインスタンスを作成しますcreateBeanInstance

最初の型を取得し、修飾子だけを取得publicファクトリメソッドによって作成されたファクトリメソッド名がある場合は、あなたが作成することができ、そして、もしあれば、復帰への直接アクセスをカスタムプロバイダのインスタンスを取得し、そうでない場合があるでしょう、何の言葉はありませんコンストラクタを分析することは、そうでない場合は、デフォルトのコンストラクタはインスタンス化、自動組立のための適切なコンストラクタを探しに行くことに。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		//检查是public修饰的
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		//扩展的实例提供器,可以直接从里面获取实例
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//有工厂方法名的,通过工厂方法获取
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;//标记下,防止重复创建同一个bean
		boolean autowireNecessary = false;//是否需要自动装配,构造器有参数的需要
		if (args == null) {//无参
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {//有解析的构造器或者工厂方法
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {//有构造参数的或者工厂方法
			if (autowireNecessary) {//构造器有参数的
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {//无参的
				return instantiateBean(beanName, mbd);
			}
		}
		//从bean后置处理器中为自动装配寻找构造方法
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		// 找出最合适的默认构造方法
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}
		// 最后才用最简单的默认构造方法
		return instantiateBean(beanName, mbd);
	}

例プロバイダobtainFromSupplier

これは主に、彼は、その後、私は本当の友達になりましたか私たち自身、当社初見の内部を拡張したものです。
主に指定されたプロバイダからget()取得するための方法beanに詰め、次にインスタンスを、そしてBeanWrapperその後のタイプ、initBeanWrapper初期化。

protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
		Object instance;

		String outerBean = this.currentlyCreatedBean.get();
		this.currentlyCreatedBean.set(beanName);
		try {
			instance = instanceSupplier.get();
		}
		finally {
			if (outerBean != null) {//不为空还是这是老的
				this.currentlyCreatedBean.set(outerBean);
			}
			else {//为空删除
				this.currentlyCreatedBean.remove();
			}
		}

		if (instance == null) {
			instance = new NullBean();
		}
		BeanWrapper bw = new BeanWrapperImpl(instance);
		initBeanWrapper(bw);
		return bw;
	}

実際の拡張ポイントInstanceSupplier

InstanceSupplierBeanDefinitionRegistryPostProcessor

登録されたポストプロセッサ、作成beanの定義と例を提供し、提供するUserDaoImple2名前はあるuserDao維持するためにMyConfig、同じメソッド名を、と呼ばれることができ、プロセッサの追加方法

public class InstanceSupplierBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        registry.registerBeanDefinition("userDao",new RootBeanDefinition(UserDao.class, () -> {
            System.out.println("UserDao自定义提供器");
            return new UserDaoImple2();
        }));
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

UserDaoImple2

public class UserDaoImple2 implements UserDao {
    @Override
    public void getUser() {
        System.out.println("UserDaoImple2 getUser");
    }

}

MyConfig

そして、メソッドプロバイダのの強さに名前をbean名が、戻りUserDaoImpleタイプ。

@Configuration
public class MyConfig {
    @Bean
    public UserDao userDao(){
        return new UserDaoImple();
    }
}

テスト

    @Test
    public void InstanceSupplierTest0() throws Exception {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(MyConfig.class);
        applicationContext.addBeanFactoryPostProcessor(new InstanceSupplierBeanDefinitionRegistryPostProcessor());
        applicationContext.refresh();
        UserDao userDao = (UserDao)applicationContext.getBean("userDao");
        System.out.println(userDao);
        userDao = (UserDao)applicationContext.getBean("userDao");
        System.out.println(userDao);
    }

結果

:提供あります
ここに画像を挿入説明
の無料プロバイダは:
ここに画像を挿入説明

これは、我々は、プロバイダ持って、それが起こったのかであるMyConfig方法では、それを動作しませんか?実際に、あるbean覆われる定義、構成の前に言えば覚えて、プロセッサはだろうMyConfig、解析され検証され、その後にロードすることがbean定義ローディングbean定義内を、あるisOverriddenByExistingDefinition方法で、既存の上書きするかどうかを決定することができるbeanの定義を私たちが提供するのでので、非常に始まるが登録されているBean定義で自己定義されたロードされた時は、あなたが直接のリターンをカバーしていない場合は、上書きするかどうかを確認するために審査されます、我々はそうで情報の方法がさえに登録決して定義:メインの判定コードがあるが、まず既存の決定、決定するためのロジックであるという事実の定義はしていませんので、同じ名前ウェルの、コンフィギュレーション・メソッドのオーバーロードクラスメソッドで登録された、それがある場合その後、カバー、およびファクトリメソッドがない場合はそれ以外の場合は、彼らが見て、カバーされる、一意ではない設定がされていないしていないでスキャンそれはまた覆われている場合は、上書きするかどうかを確認するためにされていない場合、定義のでこと、内部ではありませんあなたはカバーすることができる内部プロセッサに:MyConfiguserDaoMyConfigbean
ここに画像を挿入説明
ConfigurationClassBeanDefinitionReaderisOverriddenByExistingDefinitionbeanbeancomponent scanbeanspring

	protected boolean isOverriddenByExistingDefinition(BeanMethod beanMethod, String beanName) {
		if (!this.registry.containsBeanDefinition(beanName)) {
			return false;
		}
		BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
		//如果是ConfigurationClassBeanDefinition类型的话,且是同一个配置类的重载方法,就保存现有
		if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
			ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
			if (ccbd.getMetadata().getClassName().equals(
					beanMethod.getConfigurationClass().getMetadata().getClassName())) {
				if (ccbd.getFactoryMethodMetadata().getMethodName().equals(ccbd.getFactoryMethodName())) {
					ccbd.setNonUniqueFactoryMethodName(ccbd.getFactoryMethodMetadata().getMethodName());//设置工厂方法不唯一,说明有重载
				}
				//不覆盖
				return true;
			}
			else {
				return false;//覆盖
			}
		}
		//如果是component scan, 覆盖现有的
		if (existingBeanDef instanceof ScannedGenericBeanDefinition) {
			return false;
		}
		//如果是框架内部的,覆盖现有的

		if (existingBeanDef.getRole() > BeanDefinition.ROLE_APPLICATION) {
			return false;
		}

		//不覆盖
		return true;
	}

私たちは、論理図を描く:
ここに画像を挿入説明
見てのspringプロセッサ、設定する必要はありません変更された場合は、右変更デフォルトクラスのプロセッサの内部構成の後に何が起こるのか、定義はないだろうが。持っていましたたとえば、本当に柔軟で拡張性の良いが、あなたも、あなたがハンドルにプロセッサをカスタマイズすることができ、内部プロセッサを変更することができ、例えば、私はすべてのカバレッジを初期化するためのプロセッサを入れて、そして今私は、この拡張性を最終決定権の初期化を持っています本当に強いああ:これは悪いIの演劇である:最後に例を提供する方法を提供し、道の登録、同じ原理:MyConfigbean
ここに画像を挿入説明
spring
ここに画像を挿入説明

ここに画像を挿入説明

    @Test
    public void InstanceSupplierTest0()  {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(MyConfig.class);
        applicationContext.registerBean("userDao",UserDao.class,() -> {
            System.out.println("UserDao自定义提供器");
            return new UserDaoImple2();
        },null);
        applicationContext.refresh();
        UserDao userDao = (UserDao)applicationContext.getBean("userDao");
        System.out.println(userDao);
        userDao = (UserDao)applicationContext.getBean("userDao");
        System.out.println(userDao);
    }

彼は次の時間継続する、と思われるものについてはそう多くはなく、任意の話を書きました。

さて、今日ここに、私たちは自分自身の学習、限られた容量を理解し、偉大な神は見スプレーしないで、言い訳してください、助けの調査に希望と理解しています。

公開された235元の記事 ウォン称賛74 ビュー30000 +

おすすめ

転載: blog.csdn.net/wangwei19871103/article/details/105047258