봄 5.x를 소스 여행 열일곱 개의 getBean 세 가지 상세

doCreateBean

프로세서 전 제품은 어떤 객체가없는 경우, 당신은있을거야, 객체의 인스턴스를 반환 할 수 있습니다 doCreateBean진정으로 개체를 만들 수 있습니다. 이 방법은 매우 복잡, 우리는 느리게 실행됩니다. 첫째, 캐시 먼저 당신이 하나 개 인스턴스를 생성하지 않는 경우, 얻을 것이다 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;
	}

빈 인스턴스를 생성 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