Spring 5.x 源码之旅十六getBean详解二

Spring 5.x 源码之旅十六getBean详解二

  • doGetBean分段2
  • doGetBean分段3
    • markBeanAsCreated标记
  • doGetBean分段4(重点来了)
    • getSingleton(String beanName, ObjectFactory singletonFactory)
      • createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      • resolveBeforeInstantiation实例化前处理
        • applyBeanPostProcessorsBeforeInstantiation实例化前处理器处理
        • applyBeanPostProcessorsAfterInitialization初始化后处理器处理
  • InstantiationAwareBeanPostProcessor-扩展点
    • TestInstantiationAwareBeanPostProcessor
    • TestBean
    • MyConfig
    • 测试代码
    • 结果:
    • 返回一个JDK的动态代理-扩展点
      • TestJDKProxyInstantiationAwareBeanPostProcessor

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实例,他还没用,所以不会报错。
Spring 5.x 源码之旅十六getBean详解二_第1张图片
然后我们进行获取就报异常啦:

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怎么实现的。
正常应该这样:
Spring 5.x 源码之旅十六getBean详解二_第2张图片
处理器返回JDK动态代理后:
Spring 5.x 源码之旅十六getBean详解二_第3张图片

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讲解。

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

你可能感兴趣的:(Spring,5.x,源码之旅,Spring源码,Spring源码解析,Spring精通源码,getBean,Spring源码之旅)