Spring-IOC-实现原理详解-初探
IOC
Bean是如何注册到IOC容器中的
xml配置文件方式下Bean的注册
1 | public ClassPathXmlApplicationContext( |
- 注册xml配置文件到configLocations
- 调用refresh()进行整个Context的刷新,实际上就是整个Context的启动
- Bean的加载会读到配置文件,解析成DOM对象,将DOM对象转换成
beanDeifnition
- obtainFreshBeanFactory()
- refreshBeanFactory()
- loadBeanDefinitions(beanFactory)
- 将 beanDeifnition 存到 beanDeifnitionMap,完成这个Bean的注册
- DefaultListableBeanFactory#registerBeanDefinition
注解方式下Bean的注册
1 | // AnnotationConfigApplicationContext构造方法 |
容器启动核心 AbstractApplicationContext#refresh()
1 | // AbstractApplicationContext#refresh() |
doGetBean - Bean是如何从IOC容器中被获取到的
1 | // Demo#applicationContext.getBean |
doGetBean()方法基本上概括了整个Bean的获取过程
- 首先通过BeanName从容器中获取Bean相关的信息,并组装成RootBeanDefinition
- 通过RootBeanDefinition来创建实例对象,这里需要根据单例、多例来分别进行创建
- 将创建或者获取到的对象返回
单例对象是容器启动的时候就已经实例化好了,可以直接拿来用,当然也可以设置延迟加载
doCreateBean - Bean的创建
在判断 mbd.isSingleton() 单例以后,开始使用基于 ObjectFactory 包装的方式创建 createBean,进入后核心逻辑是开始执行 doCreateBean 操作。
1 | // AbstractAutowireCapableBeanFactory#doCreateBean |
- 在 doCreateBean 方法中包括的内容较多,但核心主要是创建实例、加入缓存以及最终进行属性填充,属性填充就是把一个 bean 的各个属性字段涉及到的类填充进去。
- createBeanInstance,创建 bean 实例,并将 bean 实例包装到 BeanWrapper 对象中返回
- addSingletonFactory,添加 bean 工厂对象到 singletonFactories 缓存中
- getEarlyBeanReference,获取原始对象的早期引用,在 getEarlyBeanReference 方法中,会执行 AOP 相关逻辑。若 bean 未被 AOP 拦截,getEarlyBeanReference 原样返回 bean。
- populateBean,填充属性,解析依赖关系。也就是从这开始去找寻 A 实例中属性 B,紧接着去创建 B 实例,最后在返回回来。
- initializeBean(beanName, exposedObject, mbd):完成 bean 的属性填充注入后,进一步初始化 bean,在此过程中产生代理对象。此时 bean 的创建工作正式完成,已经可以在项目中使用了
populateBean - bean属性填充
1 | //AbstractAutowireCapableBeanFactory#populateBean |
Bean的存储及Spring bean的三级缓存
Bean的存储
1 | // DefaultListableBeanFactory |
存储 bean 的 map 在DefaultListableBeanFactory
类中。
通常叫BeanDefinition接口为 : bean的定义对象。
可以认为BeanDefinition是一个中转站,这个中转站中,存放了所有的class对应的信息,如果是初始化,就根据BeanDefinition的属性信息去初始化。
Bean的三级缓存
采用三级缓存模式来解决循环依赖问题。
Spring只是解决了单例模式下属性依赖的循环问题;Spring为了解决单例的循环依赖问题,使用了三级缓存。
1 | //public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry |
第几级缓存 对应的map 说明
- 第1级 Map<String, Object> singletonObjects
用来存放已经完全创建好的单例 beanbeanName -> bean 实例
最基础的缓存,创建完并初始化(createBean)后的bean实例会放入,项目启动完成后获取bean实例时从此获取 - 第3级 Map<String, ObjectFactory<?>> singletonFactories
用来存放单例 bean 的 ObjectFactorybeanName -> ObjectFactory 实例
创建bean过程中用于处理循环依赖的临时缓存,由于只有在初始化时才知道有没有循环依赖,所以通过ObjectFactory临时存储
刚创建完的bean,并延迟触发循环依赖时被引用的bean需要赋值当前bean时去获取当前bean的逻辑,且获取对象会作为当前bean的最终对象 - 第2级 Map<String, Object> earlySingletonObjects
用来存放早期的 beanbeanName -> bean 实例
创建bean过程中用于处理循环依赖的临时缓存,搭配第三层缓存,用于其ObjectFactory返回对象的缓存,保证多个关联对象对当前bean的引用为同一个
一个bean在创建过程中可能会产生两个对象:
- 一个是循环依赖时需要设值给与此bean相互引用的其他bean的对象(getEarlyBeanReference)
- 一个是初始化后的对象(initializeBean)
1 | // public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory |
spring-beans
BeanFactory
BeanFactory,以Factory结尾,表示它是一个工厂(接口), 它负责生产和管理bean的一个工厂。
在Spring中,BeanFactory是工厂的顶层接口,也是IOC容器的核心接口,因此BeanFactory中定义了管理Bean的通用方法,如 getBean 和 containsBean 等,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,所以Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等。
整套初始化方法及其标准顺序为:
1 | /** |
从BeanFactory接口的结构我们可以看出,通过getBean重载方法,为我们创建不同的Bean对象。
当然其也有很多工厂实现,例如我们用的最多的DefaultListableBeanFactory,还有SimpleJndiBeanFactory、StaticListableBeanFactory等等。
Spring工厂模式的应用还加入了反射及配置。通过对各种配置,例如xml、注解等等解析成BeanDefinition,然后根据不同工厂要求通过反射创建不同的Bean对象,这样开发过程中,我们可以将需要创建的对象通过配置等方式交给Bean工厂去完成,使用时直接获取便可。
Spring 中的 BeanFactory 就是简单工厂模式的体现。根据传入一个唯一的标识来获得 Bean 对象,但是在传入参数后创建还是传入参数前创建,要根据具体情况来定。
FactoryBean
首先FactoryBean是一个Bean,但又不仅仅是一个Bean,这样听起来矛盾,但为啥又这样说呢?
其实在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
但对FactoryBean而言,这个FactoryBean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
FactoryBean表现的是一个工厂的职责。即一个Bean A如果实现了FactoryBean接口,那么A就变成了一个工厂,通过常规的ApplicationContext.getBean(beanId)
获取的不是FactoryBean这个直接对象,而是调用FactoryBean.getObject()
生成的对象;ApplicationContext.getBean(&beanId)
,加上&
才能取得FactoryBean这个对象。
FactoryBean使用场景
- Spring 的 ProxyFactoryBean
- Mybatis 中的 SqlSessionFactoryBean
- dubbo 的 ReferenceBean
FactoryBean的设计主要是为了进行扩展容器中Bean的创建方式,所以FactoryBean着重于自定义创建对象过程,同时FactoryBean都会放到容器中,FactoryBean所创建的Bean也会放入容器中。
ObjectFactory
1 | /** |
ObjectFactory则只是一个普通的对象工厂接口。
在Spring中主要两处用了它:
- Object get(String name, ObjectFactory<?> objectFactory);
这个方法的目的就是从对应的域中获取到指定名称的对象。
为什么要传入一个objectFactory呢?主要是为了方便我们扩展自定义的域,而不是仅仅使用request,session等域。 - void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue); 从这段内容中我们能知道,autowiredValue这个参数可能就是一个ObjectFactory,主要是为了让注入点能够被延迟注入。
1
2
3/**
@param autowiredValue the corresponding autowired value. This may also be an* implementation of the {@link org.springframework.beans.factory.ObjectFactory}* interface, which allows for lazy resolution of the actual target value.
**/
Spring通过这种方式注入了request、response等对象。- beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
- beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
- beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
- beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());