Spring 5.x 源码之旅-16getBean详解二

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

doGetBean分段2

我们继续上次的,上次讲了存在单例的情况,可能是普通对象,也可能是FactoryBean,是FactoryBean可能是要获取创建的对象。这次我们继续第二段。这段主要是判断是不是正在创建的原型类型,原型类型无法解决循环应用问题,会报异常。为什么原型不能循环引用呢,因为原型的定义就是每次都是需要新的对象,如果A是原型,引用B,这个时候B也是要被创建的,如果B是原型,也引用A,那A也要被重新创建,然后A里面又要引用B,又重新创建,这样下去就变成创建的死循环了,所以原型循环引用不行。如果发现父工厂存在,bean定义不存在,就会从父工厂去找,让父工厂去创建,这个情况比较少,所以暂时不深入了。

    		// Fail if we're already creating this bean instance:
    			// We're assumably within a circular reference.
    			if (isPrototypeCurrentlyInCreation(beanName)) {//原型的循环引用报错
    				throw new BeanCurrentlyInCreationException(beanName);
    			}
    
    			// Check if bean definition exists in this factory.如果bean定义不存在,就检查父工厂是否有
    			BeanFactory parentBeanFactory = getParentBeanFactory();
    			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    				// Not found -> check parent.
    				String nameToLookup = originalBeanName(name);
    				if (parentBeanFactory instanceof AbstractBeanFactory) {
    					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
    							nameToLookup, requiredType, args, typeCheckOnly);
    				}
    				else if (args != null) {
    					// Delegation to parent with explicit args.
    					return (T) parentBeanFactory.getBean(nameToLookup, args);
    				}
    				else if (requiredType != null) {
    					// No args -> delegate to standard getBean method.
    					return parentBeanFactory.getBean(nameToLookup, requiredType);
    				}
    				else {
    					return (T) parentBeanFactory.getBean(nameToLookup);
    				}
    			}

doGetBean分段3

继续下面一段,首先判断是否仅仅是检查类型,不是的话才会标记成已经创建了,或者正要创建,并且会设置需要bean定义合并标记,以便后面获得最新的bean定义。然后会处理dependsOn 依赖,有依赖的会优先处理依赖,这个后面讲。

    //标记已经创建
    			if (!typeCheckOnly) {
    				markBeanAsCreated(beanName);
    			}
    
    			try {
    				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//获取合并后的bean定义
    				checkMergedBeanDefinition(mbd, beanName, args);
    				//保证dependsOn的先实例化
    				// Guarantee initialization of beans that the current bean depends on.
    				String[] dependsOn = mbd.getDependsOn();
    				if (dependsOn != null) {
    					for (String dep : dependsOn) {
    						if (isDependent(beanName, dep)) {//循环依赖,到底谁先创建呢?
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
    						}
    						registerDependentBean(dep, beanName);
    						try {
    							getBean(dep);
    						}
    						catch (NoSuchBeanDefinitionException ex) {
    							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
    						}
    					}
    				}

markBeanAsCreated标记

其实就是放进一个alreadyCreated集合里做标记,但是这里会设置需要合并bean定义,这个在前面讲过,因为在创建之后可能会有很多处理器处理过bean定义,所以这里要把bean定义做一个合并,也就是刷新。

    protected void markBeanAsCreated(String beanName) {
    		if (!this.alreadyCreated.contains(beanName)) {
    			synchronized (this.mergedBeanDefinitions) {
    				if (!this.alreadyCreated.contains(beanName)) {//需要重新获取合并一下bean定义,以免元数据被同时修改
    					clearMergedBeanDefinition(beanName);
    					this.alreadyCreated.add(beanName);
    				}
    			}
    		}
    	}
    
    	protected void clearMergedBeanDefinition(String beanName) {
    		RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
    		if (bd != null) {
    			bd.stale = true;//需要合并
    		}
    	}

doGetBean分段4(重点来了)

我们还是来一般正常的创建吧,如果判断你是到了类型,就开始创建单例,这里传了一个lambda表达式来创建bean

    if (mbd.isSingleton()) {//如果是单例,准备创建单例
    		sharedInstance = getSingleton(beanName, () -> {
    			try {
    				return createBean(beanName, mbd, args);
    			}
    			catch (BeansException ex) {
    				destroySingleton(beanName);
    				throw ex;
    			}
    		});
    		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    	}

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

这个获取单例跟以前的不一样,需要创一个ObjectFactory方法,也就是说,可能需要调用这个方法来获取。首先还是先获取下如果存在就返回了,否则就开始创建单例,先做开始创建的标记,然后创建对象,然后清除标记,最后加入到单例集合中。

    	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    		synchronized (this.singletonObjects) {
    			Object singletonObject = this.singletonObjects.get(beanName);//获取
    			if (singletonObject == null) {
    				if (this.singletonsCurrentlyInDestruction) {//单例是否在销毁中,报异常
    					throw new BeanCreationNotAllowedException...
    				}
    				beforeSingletonCreation(beanName);//创建前做个正在创建的标记
    				boolean newSingleton = false;//是否创建单例成功,感觉这个用处不大
    				...
    				try {//调用ObjectFactory的getObject创建bean对象
    					singletonObject = singletonFactory.getObject();
    					newSingleton = true;//只要获取了就是新单例
    				}
    				catch (IllegalStateException ex) {
    					...
    				}
    				catch (BeanCreationException ex) {
    					...
    				}
    				finally {
    					...
    					afterSingletonCreation(beanName);
    				}
    				if (newSingleton) {//如果是新的单例,就加入到单例集合
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}

createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

调用ObjectFactorygetObject创建bean对象,其实里面就是这个方法,首先要进行创建类型的解析,解析过程比较复杂,后面讲,因为我们只有名字,不知道要创建什么类型,然后进行方法覆盖,主要是处理look-up方法,CGLIB动态代理实现一些look-up方法,需要检查能不能覆盖,再创建之后进行处理器处理,这个也是扩展点,然后创建。

    @Override
    	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    
    		...
    		RootBeanDefinition mbdToUse = mbd;		
    		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);//解析出bean的类型
    		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {//能解析出来,没有BeanClass只有BeanClassName
    			mbdToUse = new RootBeanDefinition(mbd);//重新创建RootBeanDefinition
    			mbdToUse.setBeanClass(resolvedClass);//设置解析的类型
    		}
    
    		try {//准备方法覆盖,处理look-up方法
    			mbdToUse.prepareMethodOverrides();
    		}
    		catch (BeanDefinitionValidationException ex) {
    			...
    		}
    
    		try {//后置处理器在实例化之前处理,如果返回不为null,直接就返回了
    			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    			if (bean != null) {
    				return bean;
    			}
    		}
    		catch (Throwable ex) {
    			...
    		}
    
    		try {//真正创建
    			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    			...
    			return beanInstance;
    		}
    		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    			...	
    		}
    		catch (Throwable ex) {
    			...
    		}
    	}

resolveBeforeInstantiation实例化前处理

在实例化之前被处理器处理。如果有处理器返回不为null的话,就直接进行初始化了,最后会设置是否被解析了。如果被处理器处理了,比如动态代理后返回,就直接返回对象了。

    @Nullable
    	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    		Object bean = null;
    		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    			// Make sure bean class is actually resolved at this point.
    			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {//非合成的,且有InstantiationAwareBeanPostProcessors
    				Class<?> targetType = determineTargetType(beanName, mbd);//获取类型
    				if (targetType != null) {
    					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
    					if (bean != null) {
    						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    					}
    				}
    			}
    			mbd.beforeInstantiationResolved = (bean != null);//是否解析了
    		}
    		return bean;
    	}
applyBeanPostProcessorsBeforeInstantiation实例化前处理器处理

InstantiationAwareBeanPostProcessor类型的处理器处理,返回的是一个Object对象, 也就是说这里可以做一些代理的事,如果发现有一个处理器返回的不是null,就直接返回了。

    @Nullable
    	protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    		for (BeanPostProcessor bp : getBeanPostProcessors()) {
    			if (bp instanceof InstantiationAwareBeanPostProcessor) {
    				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
    				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
    				if (result != null) {
    					return result;
    				}
    			}
    		}
    		return null;
    	}
applyBeanPostProcessorsAfterInitialization初始化后处理器处理

如果发现applyBeanPostProcessorsBeforeInstantiation返回的对象不是null,就说明已经有对象了,所以就会进行初始化后处理,如果返回null的话就说明不处理了,直接返回了,否则就进行处理。这里有点像装饰器,把existingBean一层层的装饰,最后返回,如果不想装饰了就直接返回。

    @Override
    	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor processor : getBeanPostProcessors()) {
    			Object current = processor.postProcessAfterInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

如果处理器没有返回对象的话,就会进行最后的对象创建doCreateBean,我们后面说吧。

InstantiationAwareBeanPostProcessor-扩展点

这个可以在创建对象之前进行干预,比如我想干坏事,我偷偷的找个地方加入一个TestInstantiationAwareBeanPostProcessor处理器,然后返回一个TestBean 的对象,这样别人就无法获取到userDao类型了。

TestInstantiationAwareBeanPostProcessor

    public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            if(beanName.equals("userDao")){
                TestBean testBean = new TestBean();
                return testBean;
            }
    
            return null;
        }
    }

TestBean

    public class TestBean {
    
    }

MyConfig

配置类里是可以获取UserDao 实例的:

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

测试代码

      @Test
        public void InstantiationAwareBeanPostProcessorTest() throws Exception {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
            applicationContext.register(MyConfig.class);
            //添加处理器,搞破坏
            applicationContext.getBeanFactory().addBeanPostProcessor(new TestInstantiationAwareBeanPostProcessor());
            applicationContext.refresh();
            UserDao userDao = (UserDao) applicationContext.getBean("userDao");
            System.out.println(userDao);
        }

结果:

在初始化的时候应该是UserDao的,我给他返回了TestBean实例,他还没用,所以不会报错。


然后我们进行获取就报异常啦:

    java.lang.ClassCastException: class com.ww.pojo.TestBean cannot be cast to class com.ww.pojo.UserDao (com.ww.pojo.TestBean and com.ww.pojo.UserDao are in unnamed module of loader 'app')

返回一个JDK的动态代理-扩展点

当然项目里没人这么干,正确的做法比如做动态代理,我再来一个JDK的动态代理试试,其实你看了这个就可以理解AOP怎么实现的。
正常应该这样:


处理器返回JDK动态代理后:

TestJDKProxyInstantiationAwareBeanPostProcessor

这个就是可以扩展返回一个JDK动态代理对象的。

    public class TestJDKProxyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            if(beanName.equals("userDao")){
                UserDao userDaoimpl=new UserDaoImple();
                UserDao userDao= (UserDao) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{UserDao.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("我是JDK动态代理的");
                        method.invoke(userDaoimpl);
                        return null;
                    }
                });
                return userDao;
            }
    
            return null;
        }
    }

这个记得要判断beanName,不然你可能把内部的处理器给改了,类型不对就报错了,比如:

    警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' is expected to be of type 'org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor' but was actually of type 'com.ww.pojo.TestBean'
    
    
    
    org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' is expected to be of type 'org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor' but was actually of type 'com.ww.pojo.TestBean'
    
    	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:395)
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)
    	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:89)
    	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
    	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
    	at com.ww.AppTest.InstantiationAwareBeanPostProcessorTest(AppTest.java:38)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    	at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

有点长了,后面我们继续doCreateBean讲解。

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值