==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍
如果你觉得对bean的创建非常熟悉了,那么可以看一下实战篇【追根究底】 为什么@Transactional注解失效了?、【追根究底】@Lazy注解为什么会失效?、【追根究底】使用@Lazy注解为什么会产生两层代理?
JavaBean的前世今生
第一块内容,思考了很久,自己的见解实在有限,不能在这么短的篇幅,将它的前世今生(POJO、JAVABEAN、EJB)讲清楚。但是不去了解这些历史,又心有不甘,所以还是选择站在前辈们的肩膀上,做一次总结。以出现的时间线来说
JavaBean 是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,set和get方法获取。-- 百度百科
使用POJO名称是为了避免和EJB混淆起来, 而且简称比较直接. 其中有一些属性及其getter setter方法的类,没有业务逻辑,有时可以作为VO(value -object)或dto(Data Transform Object)来使用.当然,如果你有一个简单的运算属性也是可以的,但不允许有业务方法,也不能携带有connection之类的方法。 – 百度百科
单纯的了解感觉还行,但是一和实际开发结合起来,就又模糊了,这玩意真的是……,我还是选择破立而生,重新开始吧……,各位看官可忽略这一段吐槽。
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;
}
FactoryBean
本身创建的时候,传的是&BeanName
,那么就需要通过这个,拿到真实的BeanName
。还有一种情况是,当为Bean
起别名到时候,也需要通过这个拿到真实的BeanName
。A
依赖了B
,C
也依赖了B
,在创建A
的时候,已经把B
创建好了,所以,创建C
的时候直接从缓存拿不是更高效吗?FactoryBean
的时候,我们其实想要的bean
是getObject
返回的那一个,而不是FactoryBean
本身,所以这里需要再处理一下。这里如果还不懂的,自己写一个测试例子,跟进去看一下就知道了(别忘了,例子我已经在上面给出啦)。@DependsOn
造成显示的循环依赖。类似下面这样。@DependsOn("b")
@Component
public class A {
}
@DependsOn("a")
@Component
public class B {
}
通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的 bean 其实是个 String,但是 requiredType 却传入 Integer类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。-- spring源码深度解析
bean
的创建过程二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
这个才是主菜,但是碍于篇幅,还是扔到下篇再讲吧,如果精简了,就太没意思了。
==>【细品springboot源码】彻底弄懂spring bean的创建过程(下)