Spring框架的七大模块
Bean定义5种作用域
Spring IoC初始化流程
☞ 第一步 Resource定位
Resource是Spring中用于封装I/O操作的接口。正如前面所见,在创建spring容器时,通常要访问XML配置文件,除此之外还可以通过访问文件类型、二进制流等方式访问资源,还有当需要网络上的资源时可以通过访问URL,Spring把这些文件统称为Resource,常用的Resource资源类型如下:
Spring提供了ResourceLoader接口用于实现不同的Resource加载策略,该接口的实例对象中可以获取一个resource对象,也就是说将不同的Resource实例的创建交给ResourceLoader的实现类来处理。
☞ 第二步 通过返回的Resource对象,进行BeanDefinition的载入
1. 什么是BeanDefinition? BeanDefinition与Resource的联系?
官方文档中对BeanDefinition的解释如下:
A BeanDefinition describes a bean instance, which has property values, constructor argument values, and further information supplied by concrete implementations.
Load bean definitions from the specified resource.
总之,BeanDefinition相当于一个数据结构,这个数据结构的生成过程是根据定位的Resource资源对象中的bean而来的,这些bean在Spring IoC容器内部表示成了BeanDefinition这样的数据结构,IoC容器对Bean的管理和依赖注入的实现都是通过操作BeanDefinition来进行的。
2. 如何将BeanDefinition载入到容器?
在Spring中配置文件主要格式是XML,对于用来读取XML型资源文件来进行初始化的IoC容器而言,该类容器会使用到AbstractXmlApplicationContext类,该类定义了一个名为loadBeanDefinitions(DefalutListableBeanFactory beanFactory)的方法用来获取BeanDefinition。
☞ 第三步 将BeanDefinition注册到容器中
最终Bean配置会被解析成BeanDefinition并与beanNames, Alias以同封装到BeanDefinitionHolder类中,之后beanFactory.registerBeanDefinition(beanName, bdHolder.gerBeanDefinition())注册到DefaultListableBeanFactory.beanDefinitionMap中。之后客户端如果要获取Bean对象,Spring容器会根据注册的BeanDefinition进行实例化。
BeanDefinition加载流程
定义BeanDefinitionReader解析xml的document,BeanDefinitionDocumentReader解析document成beanDefinition
DI依赖注入流程(实例化,处理Bean之间的依赖关系)
过程在IoC初始化后,依赖注入的过程是用户第一次向IoC容器索要Bean时触发。
☞ 依赖注入如何处理Bean之间的依赖关系
在beanDefinition载入时,如果bean有依赖关系,通过占位符来代替,在调用getBean时候,如果遇到占位符,从IoC里获取bean注入到本实例来。
Bean的生命周期
Spring的IoC注入方式
Soring的循环依赖
☞ 什么是循环依赖?
循环依赖其实就是循环引用,也就是两个或者两个以上的bean相互持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C依赖于A,如图:
Spring中循环依赖场景有:
☞ 怎么检测是否存在循环依赖?
Bean在创建的时候可以给Bean打标,如果递归调用回来发现正在创建中的话,即说明存在循环依赖。
☞ 如何解决循环依赖?
Spring的单例对象的初始化主要分为三步:(1)CreateBeanInstance实例化(调用对象的构造方法实例化对象);(2)populateBean填充属性(多bean的依赖属性进行填充);(3)InitializeBean初始化(调用spring xml中的init方法)
从上面单例bean初始化步骤可以看到,循环依赖主要发生在第一、第二部,也就是构造器循环依赖和filed循环依赖。
在Spring容器整个生命周期内,有且只有一个对象,对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
这三个缓存分别指:
创建bean的时候Spring首先从一级缓存singletonObjects中获取,如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取,如果还是获取不到就从三级缓存singletonFactories中取(Bean调用构造函数进行实例化后,即使属性还为填充,就可以通过三级缓存向外提前暴露依赖的引用值,根据对象引用能定位到堆中的对象,其原理是基于Java的引用传递),取到后从三级缓存移动到二级缓存,完全初始化之后将自己放入到一级缓存中供其他使用。
因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
Spring中使用了哪些设计模式?
AOP核心概念
解释一下AOP
传统OOP开发代码逻辑是自上而下地,这个过程中会产生一些横切性问题,这些问题与我们主业务逻辑关系不大,会散落在代码地各个地方,造成难以维护,AOP的思想就是把业务逻辑与横切的问题进行分离,达到解耦的目的,提高代码重用性和开发效率
AOP主要应用场景
AOP源码分析
AOP使用哪种代理对象
JDK动态代理
静态代理与动态代理区别
CGLIB和JDK动态代理区别