【视频来源于:B站up主孙帅suns Spring源码视频】【微信号:suns45】
作为整个spring创建对象的流程来讲,实际上包含若干个步骤
1、【第一个步骤就是getBean,是我们最开始调用的。】
2、【doGetBean【交由另外一个方法doGetBean完成后续实质性的工作内容】】
【doGetBean包含若干个环节包括对象的获取和对象的创建】
【这两个部分分别是对象的获取还有对象的创建 由这两部分构成的】
【对象的获取就是从相应的各种Map中获取这个对象,还包括父子容器】
【如果获取不到就会走下面的这个流程就是我们所说的这个对象的创建】
【对象的创建核心交给另外一个方法帮他完成相应的工作,这个方法叫做createBean来完成】
【createBean后续会交给doCreateBean】
【而doCreateBean包括几个内容,1、创建对象,2、属性填充【主要分析的是set,自动注册平常很少涉及到,在整个的属性填充实际上用的是set注入,3、初始化就是最后一个工作】
3、【到上次课为止主要讲的是属性的填充】
【属性的填充实际上 就是通过set 为这个bean 存储相应属性的值】
【分为两大类,基于bean标签的处理,基于注解的形式】
【注解指的是什么注解?@Autowired @Value】
【下面讲解的内容主要就是bean标签的属性填充再分析,注解形式@Autowired @Value是如何完成的】
【看代码】
在User类中,定义一个Address类成员变量,在配置文件中bean Address value… ref… 引入Address类,在测试类中获取user,address一定会进行注入
getName获得的是属性的名字【propertyName,是address这个string值】RuntimeBeanReferences
getValue获取的是属性原始的值【resolvedValue,是RuntimeBeanReferences这个类型】
JDK类型的是TypedStringValue,
自定义注入类型是RuntimeBeanReferences,后续类型转换之后会变成实质性的bean
转化发生的位置在哪呢?valueResolver.resolveValueIfNecessary(),进入这个方法,此时会发现 它专门处理了RuntimeBeanReferences,猜一下接下来的逻辑应该是怎么样的呢?
如果Spring在处理的过程中发现RuntimeBeanReferencens这个类型,那么spring下面的逻辑应该是什么呢?
在set注入的过程当中 spring一定会 为这个User注入Address对象,一旦分析是RuntimeBeanReferences之后,最终的目的是把RuntimeBeanReferences变成Address对象,怎么能获得这个对象呢?
这个address也是spring工厂当中我们生命的一个bean标签,也是要从工厂获取这个address,
下面的逻辑就是RuntimeBeanReferences的作用就是从工厂中获取Address对象,怎么从工厂中获得对象?beanFactory.getBean() ->doGetBean() ->createBean->doCreateBean这个流程,把获取User的过程重新来一遍。
继续这个resolveValueIfNecessary方法
1、进入resolveReference这个方法
1.1、拿bean的名字refName
1.2、如果有父亲的话,从父工厂解决问题
1.3、最终的逻辑一定会运行到this.beanFactory.getBean(refName)->doGetBean()…->doCreateBean->单实例对象的那个分支
2、Address和User创建对象相比还有属性 需要set注入,还需要走applyPropertyValues(),Address没有属性,如果有属性还会再走一遍
这就是 用户自定义类型注入的过程。
在创建bean的过程中,进行属性填充,如果是bean标签调用的就是applayPropertyValues这个函数,作为这个函数来讲,基本类型都是TypedStringValue,自定义类型都封装成了RuntimeBeanReference,会走valueResolver.resolveValueIfNecessary()这个流程
基本类型的注入靠的是convertForProperty(resolvedValue, propertyName, bw, converter)这个函数来完成的
1、首先定义了我的配置类
如果用springboot,可以换成使用springboot 专门处理yaml的注解效果是一样的
2、对应的配置文件就是app.properties
3、创建了两个类,关注 Product中 @Value id 和 @Value name
4、测试
1、通过一个AutowiredAnnotationBeanPostProcessor完成的注入过程。
2、@Autowired @Value 基于AutowiredAnnotationBeanPostProcessor来完成的
3、整个流程体现在什么位置的呢?
populateBean的if(hasInstAwareBpps){【打断点】
xxxx
}
4、打断点查看
在dubug的时候 需要对断点添加 product情况判断
把需要注入的属性PropertyValues拿出来
查看for循环遍历BeanPostProcessor,查看跟AOP相关的都是带Proxy的。
5、AutowiredAnnotationBeanPostProcessor的作用
看InjectionMetadata metadata里面就是我们需要注入的内容
metadata.inject是真正完成了注解的处理
进到这个方法中
此时element就是我们属性,遍历的就是我们的属性,拿到一个属性进行一个element.inject()
第一个遍历进去这个方法,发现field就是Product的id
beanFactory.resolveDependency把注解里面的对应的配置文件的值获取出来了,
ReflectionUtils.makeAccessible(filed)打破封装
field.set()进行赋值。
注解的形式 @Autowired @Value的整个流程就是
AutowiredAnnotationBeanPostProcessor
postProcessorProperties
metadata.inject(bean,beanName,pvs)
value=beanFactory.resolveDependency->StringValueResovler ${product.id} 替换成了1
filed.set(bean,value)
最后再次debug一下,把断点打到populateBean()方法中,执行完PostProcessor的地方,看wrappedObject属性是否有值。
把@Autowired Acount去掉,发现Account为空,有了@Autowired Account就有值了
不管通过 当如果这个类型自定义的对象时,他一定会继续通过BeanFactory#getBean() 一般情况下 指的都是Spring自己提供的BeanPostProcessor。 初始化过程中的BeanPostProcessor一般都是程序猿提供的。 Spring基础课程讲过一个概念,AOP创建动态代理它是通过什么样的方式来完成的呢? AOP创建动态代理的底层是 JDK/ Cglib,在spring当中AOP到底是通过什么技术来把动态代理 编程方式 通过切入点 原始对象 组装成切面。 AOP最终是通过BeanPostProcessor来完成的 如果你感到有困惑可以去B站找孙帅suns的基础spring课。 最终一定会跟创建对象有关,一旦用了动态代理,最终创建的是个代理对象。 有一个问题,AOP一定会在对象创建中体现,它是用BeanPostProcessor的方式来完成的,刚才也分析了整个创建对象的过程。 docreateBean 创建对象实际上创建的实际上 是原始对象,只不过就是对原始对象 Wrapper进行了一个包装。包装的目的是什么? 在解决循环引用的时候,它号称使用了3种缓存,也就是所谓的3级缓存,官方没有这个概念,所谓的这个三级缓存在整个spring的体系中没有人提过。提出这个概念的人,应该加一嘴说这是他自己提出来的而不是官方。 这个地方代理创建的时机 最后决定了 怎么解决循环引用,以及为什么循环引用要那么设计? 解决AOP动态代理的BeanPostProcessor到底是在属性填充里面做的,还是在初始化环节做的? 我们现开发代理的环境 1、引入三个依赖 2、开发一个bean 3、写一个Before实现一个接口,这和注解的@Before是一样的 4、配置在配置文件当中。 5、写代理 6、测试AOP编程 如果能在执行register之前执行AOP的打印就证明成功了。 7、查看结果 8、跟踪代码到创建对象那一行代码下面,根据debug查看值发现没有被代理的 9、跟踪到populateBean()的下一行代码查看instanceWrapper,发现没有创建代理 10、打到initializeBean()的下一行代码,发现exposedObject是代理对象,说明在初始化方法的操作中完成了代理的创建。 进入到initalizeBean这个方法中,看是BeanPostProcessorBefore帮我们做的还是 BeanPostProcessorAfter帮我们做的。 通过条件断点定位到BeanPostProcessorBefore后面和BeanPostProcessorAfter后面查看 wrappedBean是否是代理对象 最后发现 是BeanPostProcessorAfter完成了代理对象的创建。 spring防止你在初始化过程当中,会做一些额外的处理,为了保证处理的安全,所以在最后来完成代理对象的创建。 进入到applyBeanPostProcessorAfterInitialization方法里面 发现经过for循环的BeanPostProcessor处理之后才会有代理对象的产生。 ProxyTargetClass是false说明不是基于类做代理而是基于接口来实现代理的。 看这个beanPostProcessor是AspectJAwareAdvisorAutoProxyCreator来完成代理的,其实我们说的AOP通过BeanPostProcessor来完成的实际上就是AspectJAwareAdvisorAutoProxyCreator,这个地方后续还是会讲的,当前只是做一个铺垫。 经过这个beanPostProcessor处理完成之后,它应该就是一个代理对象了,可以通过debug代理验证。 查看一下current 总结:AOP的代理对象 是在初始化阶段中的applyBeanPostProcessorAfterInitialization完成的,这仅仅是它的一个位置,后面还会再讲这个代理会在别的地方进行创建的,目前创建一个对象是在BeanPostProcessor中完成的。 在populateBean方法中applyPropertyValues是处理bean标签处理xml的 在populateBean经过判断是注解处理,就会在一个for循环中,找到AutowiredAnnotationBeanPostProcessor进行处理,会把你的属性值都给提取出来,然后遍历一一注入赋值。如果是@Value类型的话,那么就是说直接通过配置文件去解析获取值,如果是@Autiwired它还是会走getBean去获取到这个bean然后再进行赋值。 不管通过 初始化呢 Aware BeanPostProcessorBefore initBean【接口】|| initMethod【自定义方法】 BeanPostProcessorBefore 有一个问题就是说AOP的本质是什么?是BeanPostProcessor AOP 代理对象的创建会在哪里进行呢? 创建对象?属性填充?初始化? 创建对象 创建的是原始对象 属性填充 只是处理属性 初始化设计到5个时机,最终经过测试是在BeanPostProcessorBefore 中完成代理对象的创建 为啥会在这个地方呢? 可能是为了安全,防止你在初始化的过程,做一些额外操作,为了保证处理的安全所以在最后做操作。 其实AOP的代理对象不止这一个地方,我们后面会见到的。9.4 初始化
9.4.1 初始化的流程
9.4.2 属性填充中的BeanPostProcessor、初始化中的BeanPostProcessor的区别是什么?
9.4.3 AOP创建动态代理它是通过什么样的方式来完成
9.5 探究AOP创建的时机
9.5.1 代理的创建是在初始化阶段完成,初始化阶段是怎么做的呢?
9.5.2 Spring为什么要在初始化过程中进行代理对象的创建呢?
9.5.3 总结
9.6 复述总结
9.6.1 自定义类型转换器是RuntimeBeanReferences处理,基本类型是由TypedStringValue进行处理
RuntimeBeanReferences处理是在这个地方
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
TypedStringValue处理是在这个地方
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
9.6.2 、注解 @Value @Autowired
9.6.3、属性填充的总结
9.6.4、初始化