本文共 4510 字,大约阅读时间需要 15 分钟。
1. spring ioc的启动过程:
spring IOC 容器的启动步骤可总结如下: 1 初始化 ApplicationContext 环境属性的初始化和验证,启动时间记录和相关标记设置,应用事件和监听者的初始化。 2 准备好容器中的 BeanDefinition (eager-initializing beans) 对 BeanDefinition 的解析、扫描和注册,BeanDefinition 的扫描和注册大致可以分为 XML 和注解两种,两种方式各自使用的组件有所不同,该步骤的时间也可以在最前面。 3 初始化 BeanFactory 准备好 BeanFactory 以供 ApplicationContext 进行使用,对接下来将要使用到的 Bean 进行实例化,资源进行准备,属性进行设置。 4 注册 BeanPostProcessors BeanPostProcessors 是进行扩展的关键组件,需要在该步骤中进行注册,可分为两种类型: 一种是框架使用者提供的,用于特定业务功能的,另一种是框架开发者提供的,用于扩展框架功能。 5 调用 BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor 是一种功能增强,可以在这个步骤添加新的 BeanDefinition 到 BeanFactory 中。 6 调用 BeanFactoryPostProcessor BeanFactoryPostProcessor 是一种功能增强,可以在这个步骤对已经完成初始化的 BeanFactory 进行属性覆盖,或是修改已经注册到 BeanFactory 的 BeanDefinition。 7 初始化 MessageSource 和 ApplicationEventMulticaster MessageSource 用于处理国际化资源,ApplicationEventMulticaster 是应用事件广播器,用于分发应用事件给监听者。 8 初始化其他 Bean 和进行其他的的上下文初始化 主要用于扩展 9 注册 ApplicationListene 将 ApplicationListene 注册到 BeanFactory 中,以便后续的事件分发 10 实例化剩余的 Bean 单例 步骤 4 到 9 都对一些特殊的 Bean 进行了实例化,这里需要对所有剩余的单例 Bean 进行实例化 11 启动完成 资源回收,分发"刷新完成"事件2. spring获取和实例化bean的过程:
Spring是通过递归的方式获取目标bean及其所依赖的bean的; Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。 结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。3. bean实例化的过程
createBeanInstance 调用对象的构造方法 实例化对象 populateBean 填充属性 为多bean的依赖属性进行填充 initializeBean 调用spring的init方法 初始化 即 创建对象(分配空间)-> 属性填充(设置对象属性)-> 初始化 分析可知 对象的循环依赖主要会发生在第一步构造器循环依赖和setter循环依赖 构造器循环依赖问题: this .singletonsCurrentlylnCreation.add(beanName)将当前正要创建的bean 记录在缓存中 Spring 容器将每一个正在创建的bean 标识符放在一个“当前创建bean 池”中, bean 标识 柏:在创建过程中将一直保持在这个池中,因此如果在创建bean 过程中发现自己已经在“当前 创建bean 池” 里时,将抛出BeanCurrentlylnCreationException 异常表示循环依赖;而对于创建完毕的bean 将从“ 当前创建bean 池”中清除掉。 setter循环依赖 解决方案: 三级缓存 singletonFactories : 进入实例化阶段的单例对象工厂的cache (三级缓存) earlySingletonObjects :完成实例化但是尚未初始化的,提前暴光的单例对象的Cache (二级缓存) singletonObjects:完成初始化的单例对象的cache(一级缓存)一级缓存:用于存放完全初始化好的 bean **/private final MapsingletonObjects = new ConcurrentHashMap (256);/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */private final Map earlySingletonObjects = new HashMap (16);/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */private final Map > singletonFactories = new HashMap >(16);/**bean 的获取过程:先从一级获取,失败再从二级、三级里面获取创建中状态:是指对象已经 new 出来了但是所有的属性均为 null 等待被 init*/
检测循环依赖的过程如下:
A 创建过程中需要 B,于是 A 将自己放到三级缓里面 ,去实例化 B
B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了! 然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A B 顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态) 然后回来接着创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面4. spring如何实现单例模式
使用单例注册表hashmap结构,若定义为单例模式 则检查注册表 根据beanName 检查为null时才创建bean 然后向注册表注册。
5. bean的创建过程转换beanName
1.1 处理FactoryBean,比如beanName 为 &user,此时会将& 截取掉 1.2 根据beanName查找真正的Name。比如我们定义了一个bean,id=“user”,name=“student”,alias=“teacher”。那么我们在getBean(name)时,name 传user,student,teacher 任何一个都可以得到我们定义的bean,切转换后的beanName是 user。尝试从缓存或者提前暴露的BeanFactory中获取实例
bean的实例化(存在FactoryBean的情况)
3.1 当前bean非FactoryBean,直接返回 3.2 当前bean为FactoryBean,则调用被覆盖的getObject()方法获取实例。原型类型循环引用的检查(多例模式下的循环引用检查)
尝试从父类工厂中实例化bean
5.1 parentBeanFactory 不为空,且parentBeanFactory 包含要查找bean的定义。即通过beanName,能找到BeanDefinition 5.2 满足条件1,则尝试从parentBeanFactory中加载bean转换RootBeanDefinition,并合并父类属性
6.1 从缓存(容器初始化时解析配置文件得到并存入缓存)中获取GenericBeanDefinition,并将其转换为RootBeanDefinition。spring源码系列-容器之XmlBeanFactory 6.2 如果parent不为空,则需要将parent的属性也合并进来。查找并实例化依赖-depend on
7.1 查找依赖-dependOn(这里的依赖,指的不是我们常说的依赖注入属性。而是当前bean可能用到特定的bean,而这个特定的bean 要放在当前bean之前加载。) 7.2 初始化依赖-dependOn根据不同的scope做bean的创建
8.1. 尝试从缓存中加载 8.2. 如果缓存不存在,则将bean标记为正在创建 8.3. 调用ObjectFactory.getObject()方法创建bean 8.4. 移除正在创建状态 8.5. 删除各种创建时状态,并添加缓存8.3.1ObjectFactory.getObject()大致包含如下流程:
a1. 处理MethodOverrides b2. 实例化的前置处理 c3. 根据不同的策略实例化bean,并包装成beanWapper d4. 提前暴露beanFactory e5. 属性填充 f6. 调用初始化方法,即各种处理器 g7. 注册销毁相关方法7. spring 实现aop
如果目标类实现了InvocationHandler接口,直接使用jdk动态代理。否则使用CGLIB
主要执行时的invoke步骤:8. spring aop 应用场景
权限、缓存、日志。转载地址:http://menhb.baihongyu.com/