17、Spring5.x源码之旅十七getBean详解三

  • doCreateBean
    • createBeanInstance创建bean实例
    • obtainFromSupplier实例提供器
  • InstanceSupplier扩展点实战
    • InstanceSupplierBeanDefinitionRegistryPostProcessor
    • UserDaoImple2
    • MyConfig
    • 测试
    • 结果

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创建bean实例

首先获取类型,然后获取修饰符,只有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定义,所以在MyConfiguserDao方法加载的时候就会进行判断,看是否要进行覆盖,如果不覆盖就直接返回了,所以我们MyConfig里的方法信息压根就没注册进bean定义:
*
主要的判断代码就是ConfigurationClassBeanDefinitionReaderisOverriddenByExistingDefinition,其实是有个判断逻辑,首先是判断已存在的bean定义是不是和bean注册方法同一个配置类的重载方法,因为同名嘛,如果是的话就不覆盖,且设置工厂方法不唯一,否则要覆盖,如果不是,就看是不是component scan扫描进来的bean定义,是的话要覆盖,如果不是就看是不是内部的,如果是也覆盖,这么说我们可以覆盖spring内部的处理器啦:

	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内部的默认的配置类处理器改了之后会怎么样吧,如果改了就不会有配置处理器处理了,MyConfig里的bean定义也不会有了:
*
不得不说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);
    }

写了那么多,好像又没讲什么,下次继续吧。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。