Spring Bean怎么初始化
导读:本文共24011.5字符,通常情况下阅读需要80分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 前言做Java都有很多年了,一直有一个疑惑: Spring 如何初始化bean,怎么调用反射实例化对象的,自己动手来解除这个疑惑。 过去我认为spring bean对象实例化一直都是由BeanPostProcessor接口实现类去做的,我就是不知道具体那个实现类。三级缓存为什么面试官特别喜欢问创建bean的三级缓存,主要是因为bean创建都是伴随着三级缓存之间的... ...
目录
(为您整理了一些要点),点击可以直达。做Java都有很多年了,一直有一个疑惑: Spring 如何初始化bean,怎么调用反射实例化对象的,自己动手来解除这个疑惑。 过去我认为spring bean对象实例化一直都是由BeanPostProcessor接口实现类去做的,我就是不知道具体那个实现类。
为什么面试官特别喜欢问创建bean的三级缓存,主要是因为bean创建都是伴随着三级缓存之间的转换完成的,对象不同状态分别存在不同缓存中,下面我会在分析代码时,顺便支持对象如何在缓存中流转的。 先了解下spring 三级缓存。
三级缓存主要作用: 创建对象ObjectFactory首先放入三级换缓存中,当调用getObject 创建实例时,会将创建好对象加入二级缓存中,并且删除三级中缓存,当对象已经完成初始化方法和属性注入,再将缓存添加到一级缓存中,并且删除二级缓存。
从源头开始找,所有spring bean 初始化都是由AbstractBeanFactory.doGetBean
方法实现的。下面我将源码减除臃肿部分,贴出来。
大概总结一下上面代码流程:
先从三级缓存中获取,如果缓存中都没有。再去判断是否存在父容器,从父容器中获取。没有正式进入bean 初始化流程,先根据beanName 获取到RootBeanDefinition,bean类元信息、先处理dependsOn中bean,保证bean依赖的创建顺序,下面会说明org.springframework.context.annotation.@DependsOn
这个注解。下一步按照不同scope 进行bean 对象初始化。初始化流程就是这样,我们将目光放在单例bean 如何实例化,集中关注AbstractAutowireCapableBeanFactory.createBean
获取注册一个单例对象
@DependsOn
注解意思是实例化某个对象依赖于某一个实例化,但是不需要持有这个实例对象。比如bean A上 需要依赖bean b才能实例化,但是bean b 不需要作为他的属性,常常用于不同实例实例化顺序标记。
看下getSingleton方法
添加到一级缓存则说明bean已经完成实例化,可以正常使用了。下面看下如何进行实例化和属性注入的。
下面进入AbstractAutowireCapableBeanFactory.createBean
这里逻辑就比较简单了 ,克隆一份RootBeanDefinition用于初始化对象,resolveBeforeInstantiation 主要用于初始化代理对象情况,主要使用BeanPostProcessor子类InstantiationAwareBeanPostProcessor实现方法去实现对象初始化,并且在实例化成功后在调用后置方法进行对象依赖注入,这里可以看见此方法返回对象直接跳出方法栈,这里可以看出单例和代理对象还是有区别的。单例对象初始化就在doCreateBean 实现了
下面就是AbstractAutowireCapableBeanFactory.doCreateBean
非常接近对象如何实例化的了
这里代码主要分成三部分
初始化实例,创建对象完成,并且添加到3级缓存。第3级缓存常常用于存储代理对象,因为有些类需要动态代理方法,需要生成代理对象,会委派给第三级缓存方法ObjectFactroy去实现的,普通对象如果不需要会直接返回。
对实例化bean进行属性注入
执行初始化方法,DisposableBean接口加入到disposableBeans容器中
实例化方法instantiateBean最终会调用SimpleInstantiationStrategy.instantiate 进行实例化
这里要注意下先判断bean是否有方法重写的,没有则使用反射生成的构造器,有就使用gclib方式创建代理对象,具体实现方式就在org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate
,有兴趣同学可以去学习下。 到此一个简单bean实例化完成了。
下面进入IOC另一个特点,bean注入,先从AbstractAutowireCapableBeanFactory.populateBean
方法开始
小知识点: AutowireCapableBeanFactory.AUTOWIRE_NO 表明不会对当前Bean进行外部类的注入,常规使用@Autowire、@Resource 都是这类型 剩下三种都是通过xml 或者 AutowireCapableBeanFactory.autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) 进行设置autowireMode 。
根据上面代码可以知道主流程bean注入都是由InstantiationAwareBeanPostProcessor 进行处理的,简单说明接口方法
InstantiationAwareBeanPostProcessor 接口实现类主要分3个
ConfigurationClassPostProcessor:看类名就知道处理@Configuration实例化,并没有属性注入逻辑,不详讲略过。
CommonAnnotationBeanPostProcessor:这个类就是实现bean注入,但是是实现JSR-250 注解、@Resource,@EJB、@WebServiceRef,@WebServiceContext,@PostConstrusct、@PreDestory这些注解实现。
AutowiredAnnotationBeanPostProcessor:实现 @Autowired、@Value注入,并且支持JSR-330's @Inject,主要分析这个类就可以知道bean 注入的。
在初始化时就将支持注解加入集合中,再使用扫描器去扫描方法、构造器、字段,如果有这些注解就进行注入。
看下怎么判断是否需要注入的
AccessibleObject 是Method、Field、Constructor 父类。
InjectionMetadata 主要是集合bean需要被注入类型,因为已经解析过bean Class信息了,相当于解析结果装起来
看下如何去扫描方法、字段的
逻辑非常简单,就是根据给定注解去class获取指定的注解,从而获取到需要注入类型,但是几行简单的代码可以看出强大编码能力,学习了????。 现在需要注入对象已经获取到,看如何注入吧
主要核心是如从缓存获取到需要注入类型实例在beanFactory.resolveDependency
中 进入DefaultListableBeanFactory看下
@Lazy 使用注解修饰bean 或者Class,在容器初始化化时不会立刻创建,只要需要使用bean才会创建的。 根据类型Optional、ObjectFactory、Provider,还有懒加载情景不同的处理,这些处理本质都是要调用doResolveDependency方法初始化对象,无论那种对象都要 获取原始对象然后再交给这些接口去包装增强。
这个方法简单做个总结,先是处理 @Value 情况,然后通过findAutowireCandidates 通过类型去容器中获取实例,如何实例还没有初始化,就会调用上面那个初始化过程,将初始化对象返回。根据注入类型进行相应处理,像stream、Collection,这些混合类型都是直接添加进去。如果出现了一个类型多个bean情况,这时就是就是@Primary、@Priority这些注解来判断或者根据属性名去和beanName匹配,最后将bean对象返回。 这里就简单看完一个bean初始化流程了。
Spring Bean怎么初始化的详细内容,希望对您有所帮助,信息来源于网络。