createBean方法的执行流程如下:
在AbstractBeanFactory的doGetBean的创建bean的方法里打上断点:
多放行几次看到了自定义的bean:
step into之后来到AbstractAutowireCapableBeanFactor的createBean
中:
1 | java复制代码protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) |
最开始是BeanDefinition的定义,由于之前以及定义了BeanDefinition,所以要根据Definition的属性创建出来bean实例,这里用RootBeanDefinition
接收容器中获取到的BeanDefinition实例。
1 | java复制代码RootBeanDefinition mbdToUse = mbd; |
接下来尝试会用类加载器加载出class对象
1 | java复制代码Class<?> resolvedClass = resolveBeanClass(mbd, beanName); |
进入到resolveBeanClass
:
1 | java复制代码protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch) |
如果是注解方式定义的话,会执行
1 | java复制代码if (mbd.hasBeanClass()) { |
如果是xml方式定义的话,会执行来做解析的工作
1 | java复制代码doResolveBeanClass(mbd, typesToMatch); |
doResolveBeanClass方法里有很多classLoader,即调用事先保存的各种各样的类加载器去尝试加载class对象,由于class对象和类加载器一一对应,所以class对象会存在于其中的一个类加载器中,通过该加载器找到了对应的class对象之后,就会用对应的classLoader加载出对象来
回到createBean,下面如果获取到的class对象不为空,并且当前的BeanDefinition在解析之前没有class对象,但是却有className时(对应xml方式),此时就会拷贝一个RootBeanDefinition
的副本,然后给这个副本设置上先前解析出来的class对象实例。
这样做的目的是不希望将解析的class绑定到缓存里的BeanDefinition,因为class有可能是每次都需要动态解析出来的。
1 | java复制代码if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { |
注解方式不会执行上面那个if,所以会来到下面这个逻辑
1 | java复制代码mbdToUse.prepareMethodOverrides(); |
该方法判断BeanDefinition是否有定义方法的覆盖
1 | java复制代码public void prepareMethodOverrides() throws BeanDefinitionValidationException { |
prepareMethodOverride先获取需要覆盖的方法数量,如果count==1则不存在重载,在使用CGLIB增强阶段就不需要进行校验了,直接找到某个方法进行增强即可,否则在增强阶段还需要做特殊的处理
1 | java复制代码protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { |
样例:
1 | xml复制代码<bean id="my TestBean" class="io.spring.test.MyTestBean"> |
对于replaced-method,会去验证一下MyTestBean里是否有changedMethod这个即将被替换的方法,对于lookup-method,如果该属性存在,则会去判断一下Teacher这个bean里是否有getUserBean这个方法,没有则报错。
回到createBean,通过方法覆盖验证之后来到
1 | java复制代码Object bean = resolveBeforeInstantiation(beanName, mbdToUse); |
主要是执行某些类型的后置处理器的操作。
1 | java复制代码@Nullable |
Spring在AOP过程中产生的中间代理类就是isSynthetic的,此时的targetType是自己定义的WelcomeController,进入到applyBeanPostProcessorsBeforeInstantiation方法里:
1 | java复制代码protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) { |
这里使用了责任链模式(Spring中的后置器基本都会使用责任链模式来处理),依次遍历实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor实现类,并调用类里面的postProcessBeforeInstantiation看看谁来负责对bean实例的创建,如果去处理了并有了结果,就会立即返回,只要某一个后置处理器返回了结果,就会阻止后面后置处理器的执行。
只要
1 | java复制代码Object bean = resolveBeforeInstantiation(beanName, mbdToUse); |
可以获取到bean实例,则会终止后续创建bean的流程,此时就表明bean实例的创建被用户接管了,Spring容器可以不用去创建了。
继续resolveBeforeInstantiation,如果bean实例已经被创建出来的话,就会执行
1 | java复制代码bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); |
前面按理说已经执行了初始化,所以这里就应该执行初始化之后的操作,进入到applyBeanPostProcessorsAfterInitialization:
1 | java复制代码public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) |
同样使用了责任链模式,但相比先前这里不局限于InstantiationAwareBeanPostProcessor,而是所有的BeanPostProcessor,只要前一个执行返回结果,当前就可以拿到上一次执行后的结果,直到获取不到结果就返回。
Spring中的拦截器都是用到了后置处理器,使用责任链的模式来层层处理。
resolveBeforeInstantiation最后如果bean不会空则就打上已经处理过的标记。
回到createBean,此时会来到doCreateBean来让Spring创建Bean容器了。
本文转载自: 掘金