2023-09-16  阅读(3)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105047258

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);
        }

结果

有提供器的:

202309162312200181.png
无提供器的:

202309162312205682.png

这个是怎么回事呢,有了提供器后我们MyConfig里的方法不起作用啦?是的,其实是bean定义被覆盖了,还记得前面讲的,配置类处理器会对MyConfig进行解析,验证,然后加载bean定义,在加载bean定义的里面,有个isOverriddenByExistingDefinition方法,可以判断是否要覆盖现有的bean定义,因为我们自定义的提供器在最开始的时候就已经注册了bean定义,所以在MyConfiguserDao方法加载的时候就会进行判断,看是否要进行覆盖,如果不覆盖就直接返回了,所以我们MyConfig里的方法信息压根就没注册进bean定义:

202309162312210453.png
主要的判断代码就是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;
    	}

我们画个逻辑图:

202309162312214834.png
来看下把spring内部的默认的配置类处理器改了之后会怎么样吧,如果改了就不会有配置处理器处理了,MyConfig里的bean定义也不会有了:

202309162312219255.png
不得不说spring真的很灵活,扩展性很好,你甚至可以改变内部的处理器,你可以自定义处理器来处理,比如我把初始化的处理器全部覆盖了,现在初始化我说了算,这个扩展性真的很强啊:

202309162312225746.png
这样就被我玩坏了:

202309162312231357.png
最后再提供一种实例提供器的方法, 注册的方式 ,原理一样的:

        @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);
        }

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

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


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文