==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍
如果你觉得对bean的创建非常熟悉了,那么可以看一下实战篇【追根究底】 为什么@Transactional注解失效了?、【追根究底】@Lazy注解为什么会失效?、【追根究底】使用@Lazy注解为什么会产生两层代理?
-
JavaBean的前世今生
第一块内容,思考了很久,自己的见解实在有限,不能在这么短的篇幅,将它的前世今生(POJO、JAVABEAN、EJB)讲清楚。但是不去了解这些历史,又心有不甘,所以还是选择站在前辈们的肩膀上,做一次总结。以出现的时间线来说- JavaBean
JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。-- 百度百科
- Enterprise Java Bean(EJB)
可以看EJB到底是什么,真的那么神秘吗??这篇文章。读完这篇文章后,我感觉我懂了,但是再看评论,我又模糊了。历史的事情,你要是没经历过,真的婆说婆有理,公说公有理,完全搞不懂……,算了,让它随风而去吧。 - Plain Ordinary Java Object(POJO)
使用POJO名称是为了避免和EJB混淆起来, 而且简称比较直接. 其中有一些属性及其getter setter方法的类,没有业务逻辑,有时可以作为VO(value -object)或dto(Data Transform Object)来使用.当然,如果你有一个简单的运算属性也是可以的,但不允许有业务方法,也不能携带有connection之类的方法。 – 百度百科
单纯的了解感觉还行,但是一和实际开发结合起来,就又模糊了,这玩意真的是……,我还是选择破立而生,重新开始吧……,各位看官可忽略这一段吐槽。
- JavaBean
-
Spring Bean的前世今生
突然觉得这个的历史可比JavaBean简单多了,我也找到一篇讲得比较好的文章为什么要有Spring?,可以作为简单了解。其实真正想去深入了解,还得去看书,单单是看网上的博客,只能是片面的知识。 -
bean创建的地方?
好了,终于到源码剖析的部分了,尽情享受吧!
代码,就简单的三个类@Component public class A { @Autowired B b; } @Component public class B { } @Aspect @Component public class C { @Pointcut("execution(public * com.acme.lazydemo.A.*(..))") public void myAnnotationPointcut(){ } @Around("myAnnotationPointcut()") public void around(JoinPoint joinPoint){ } }
- 第一个创建
bean
的地方
将断点打到AbstractBeanFactory->getBean
中(有三个,都打上),debug运行,马上就会到这里。
接着,如何找到是哪里调用getBean
的呢?可以看到左下角有个栈,我们可以回溯回去。发现在prepareContext
这里的时候就有bean的创建了。这是系统的bean,我们现在不需要管。 - 第二个创建
bean
的地方
继续往下运行,发现第二个创建bean
的地方invokeBeanFactoryPostProcessors
,这个创建bean
工厂后置处理器的地方,目前也不需要管。
但是值得一说的是,如果你自己实现了一个BeanFactoryPostProcessor
,那么也会在这个地方被创建。例如@Component public class D implements BeanFactoryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } }
- 第三个创建
bean
的地方
接着继续运行,发现第三个创建bean
的地方registerBeanPostProcessors
,这里是创建bean
后置处理器的地方,和第二个同理,只要实现了BeanPostProcessor
的bean
都会在这里创建。
- 第四个创建
bean
的地方
接着继续运行,发现第四个创建bean
的地方preInstantiateSingletons
,这里就是创建bean
的最后一个地方,也是最集中的一个地方,所有非懒加载的bean
都在这里创建了。
可以看一下这个方法的源码,看注释可以知道,这个地方是实例化所有非懒加载的单例。@Override public void preInstantiateSingletons() throws BeansException { …… // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 实例化所有非懒加载的单例 // Trigger initialization of all non-lazy singleton beans... for (String beanName : beanNames) { //合并bean的定义 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //先判断是否是FactoryBean if (isFactoryBean(beanName)) { //拿到FactoryBean本身的实例 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); …… if (isEagerInit) { //如果需要提前创建,那么就通过不传&,拿到真实的bean,也就是FactoryBean中的getObject方法返回的对象 getBean(beanName); } } else { //普通Bean创建 getBean(beanName); } } } // Trigger post-initialization callback for all applicable beans... …… }
- 第一个创建
-
剖析创建Bean的源码
代码入口是preInstantiateSingletons
方法,这里不重复贴出来。-
为什么要有
getMergedLocalBeanDefinition
这个方法?
可以看到,BeanDefinition
的实现类有很多,所以getMergedLocalBeanDefinition
方法只是将它们的定义合并,并没有做了什么高大上的事情。 -
FactoryBean
为什么会单独处理?
这里可以加个类来测试一下@Component public class F implements FactoryBean<E> { @Override public E getObject() throws Exception { return new E(); } @Override public Class<E> getObjectType() { return E.class; } }
接下来,断点跟踪一下,可以看到,返回的是
E@3589
这个对象。注:FactoryBean的作用就是,告诉spring,从我这里拿bean。也就是从getObject方法中返回的对象。
然后跳过所有,运行到测试的地方,可以看到,实际返回的E@4023
这个对象。这就证明了,FactoryBean
返回的实际上是getObject
创建的对象。注:FactoryBean不能被切,如果被AOP了,那么就拿不到getObject中创建的对象,这是实测结果。所以开头的C类,只切了A这个类。
所以在这里单独处理就是因为这个原因,可以看到代码中先判断是否是FactoryBean
,然后拿到FactoryBean
本身的实例,再判断是否需要提前实例化,然后通过getBean
拿到getObject
中的对象。 -
普通
bean
的创建过程一
这里就拿bean A
的创建演示。重新启动,断点继续下到preInstantiateSingletons
中,如图
接着继续跟进去,getBean
->doGetBean
,说到这里,已经基本到高潮部分了,部分精彩剧情都在这里。
因为这个方法的代码实在太长了,所以把这个代码主要关注部分贴出来慢慢解释就行,我会进行标号,对着标号说。protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //1.获取真实的BeanName final String beanName = transformedBeanName(name); Object bean; //2.尝试从缓存中获取单例 // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { …… //3.这一步是为了类似FactoryBean这种特殊的Bean而做的处理 //由之前的分析可以知道,sharedInstance可能是FactoryBean本身,并不是getObject方法返回的对象,所以需要拿到真实的对象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //4.只有在单例情况才会尝试解决循环依赖,原型模式情况下是不支持的 // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //5.如果beanDefinitionMap中也就是在所有已经加载的类中不包括beanName则尝试从parentBeanFactory中查找 // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { …… } //6.类型检查不需要标记该bean已创建 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { …… //7.这里就是@DependsOn注解的实现之处,如果A必须依赖于B才能创建,那 //么必须先创建B,不能使用@DependsOn造成显示的循环依赖,直接报错。 //例如A中@DependsOn("b"),B中@DependsOn("a") // 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)) { …… } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { …… } } } //8.单例的创建 // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { …… } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //9.原型bean创建 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } //10.指定的scope上实例化bean else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); …… } } //11.检查需要的类型是否符合bean的实际类型,如果不符合,会尝试使用类型转换器转换 // Check if required type matches the type of the actual bean instance. if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); …… return convertedBean; } catch (TypeMismatchException ex) { …… } } return (T) bean; }
- 获取真实的BeanName
为什么会有这一步呢?前面说过,FactoryBean
本身创建的时候,传的是&BeanName
,那么就需要通过这个,拿到真实的BeanName
。还有一种情况是,当为Bean
起别名到时候,也需要通过这个拿到真实的BeanName
。 - 尝试从缓存中获取单例
为什么会有这一步呢?第一个是为了解决循环依赖,这个很好理解。第二个是为了不重复创建,比如A
依赖了B
,C
也依赖了B
,在创建A
的时候,已经把B
创建好了,所以,创建C
的时候直接从缓存拿不是更高效吗? - 拿到真实的bean
为什么会有这一步呢?前面说FactoryBean
的时候,我们其实想要的bean
是getObject
返回的那一个,而不是FactoryBean
本身,所以这里需要再处理一下。这里如果还不懂的,自己写一个测试例子,跟进去看一下就知道了(别忘了,例子我已经在上面给出啦)。 - 原型模式循环依赖检测
原型模式不支持循环依赖检测,因为原型bean是不会放在缓存里的,就没有提前暴露引用这么一说,所以肯定是会报错的。 - 尝试从parentBeanFactory中查找bean定义
这个说实话,我没接触过这类case,所以这个跳过了,不说了。 - 是否是类型检查
这个我不是很理解,是不是类型检查,不是都接着往下走,创建bean了吗?可能水平有限,没找到对应的源码吧。 - @DependsOn注解的实现
没看源码之前,我也没想到这个注解居然实现如此简单,就是一个判断,如果某个类型有这个注解,然后解析注解中的类,并先创建它们,之后再回来继续创建自己。值得注意的是,不能使用@DependsOn
造成显示的循环依赖。类似下面这样。@DependsOn("b") @Component public class A { } @DependsOn("a") @Component public class B { }
- 单例的创建
这个是重点,下面会单独讲。 - 原型bean创建
这个用得较少,跳过。(实际项目中没用过,也没研究过,所以不献丑了) - 指定的scope上创建bean
同上 - 是否需要类型转换
引用书上的解释,这个我实际也没怎么遇到过通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的 bean 其实是个 String,但是 requiredType 却传入 Integer类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。-- spring源码深度解析
- 普通
bean
的创建过程二
啊,感觉路才刚刚走了1/5,这bean
的创建过程真的是太复杂了……,站起来,继续撸!接下来,看看单例的创建,方法是createBean
,同样,将需要关注部分的源码贴出来,标号,对着说
@Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; //1. 解析`beanClass` // Make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved Class // which cannot be stored in the shared merged bean definition. Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { //2.对override属性进行标记及验证 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { …… } try { //3.给BeanPostProcessor改变bean的机会 // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { …… } try { //4.开始创建bean Object beanInstance = doCreateBean(beanName, mbdToUse, args); return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { …… } catch (Throwable ex) { …… } }
-
解析
beanClass
这里我其实也不是很懂,按照英文注释翻译过来就是,有些bean
的定义是动态的,不会存在mdb里面,所以这里需要尝试进行解析。因为不知道case,所以也演示不了。 -
对
override
属性进行标记及验证
这个我也没用过,书里倒是解释了一番,这里引用一下很多读者可能会不知道这个方法的作用,因为在 Spring 的配置里面根本就没有诸如override-method之类的配置,那么这个方法到底是干什么用的呢?
其实在 Spring 中确实没有 override-method 这样的配置,但是如果读过前面的部分,可能会有所发现,在Spring配置中是存在lookup-method和replace-method的,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,而这个函数的操作其实也就是针对于这两个配置的。-- spring源码深度解析书中花了一大段来讲
prepareMethodOverrides
的源码,最后得出了这么一个结论。所以感觉这一部分还是挺有意思的,但可惜没研究过,所以这里就不展开了。但是,这里要提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。但是,Spring将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证,正可谓一箭双雕。-- spring源码深度解析
-
给BeanPostProcessor改变bean的机会
这个就好理解了,不理解的,推荐看一下springboot之BeanPostProcessor功能及例子(一)这篇文章,就马上明白了。
resolveBeforeInstantiation
方法里还有一些好玩的地方,但是碍于篇幅,以及不是主线剧情,我就不展开讲它了。 -
开始创建bean
这个才是主菜,但是碍于篇幅,还是扔到下篇再讲吧,如果精简了,就太没意思了。
-
-