IOC 控制反转
1. Spring IOC 的原理?
spring ioc 即控制反转,就是将我们创建和管理对象交给了spring进行处理; 我们只需要通过配置文件描述对象, 容器加载配置文件描述,并将其转换为Bean Difinition , 然后通过BeanFactory 来生产对象,当然单利在创建一次后会缓存在bean容器中。
Spring IOC 主要实现依赖于 工厂模式 + 反射;
2. Spring IOC 容器有什么?
- BeanFactory
- ApplicationContext
BeanFactory - BeanFactory 就像一个包含 bean 集合的工厂类。它会在客户端要求时实例化 bean。 ApplicationContext - ApplicationContext 接口扩展了 BeanFactory 接口。它在 BeanFactory 基础上提供了一些额外的功能。
3. Spring load 作为bean定义的过程?
定义bean可以通过xml <bean> 标签的形式进行配置;其次现在使用注解形式进行配置;
- 在 @Configuration 类文件中通过 @Bean进行配置
- 通过@ComponentScan 包,@server,@controller等进行配置
- 通过 @Import进行导入;
@Import // 导入一个普通类到spring容器,可以有几种方式:
@import(value = {InstC.class})
// 通过在注册器中,构造bean定义并通过import导入,spring整合mybatis
@import(value = {ImportBeanDifinitionRegister.class})// 通过类的相对类名,包,可以导入批量,实现importSelector ,springboot 自动装配原理
@imoprt(value = {ImportSelector.class})
加载过程是:
- .class 的字节码文件,通过JVM 类加载器加载到内存,
- 通过@import,@componentScan,@Bean 等将其转换为Bean Definition,
- 将其存储在BeanDefinitionMap 中,key BeanName,value 就是对象;
4. Spring Bean definition 定义 ?
spring 将配置解析为bean定义:
class: 类路径名
scope: 单利,原型
autowaremode: 注入模型
lazyInit 是否是懒加载
默认注入模型是 0, 在使用的时候必须加@Autoware
可以在后置处理器修改注入模型,1,2 分别是byName, byType, 在类中必须写setXXX方法 它就会自动的注入进去;
懒加载,依赖,构造参数等记录;
5. BeanFactoryPostProcessor
spring 提供一个扩展机会再bean definition 还没进行实例化的时候,还可以对其进行扩展。
修改我们bean definition 的属性;
BeanFactoryPostProcessor 修改的是我们的bean定义,相当于修改的是类型,而不是具体的实例;
BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,在父类的基础上,增加了新的方法,允许我们获取到BeanDefinitionRegistry,从而编码动态修改BeanDefinition。例如往BeanDefinition中添加一个新的BeanDefinition。
BeanDefinitionRegistryPostProcessor,这也就是我们在@import中实现第二种方法的原理;
也就是在getBean 之前进行调用;
6. BeanPostProcessor
public interface BeanPostProcessor {
//bean初始化方法调用前被调用
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
//bean初始化方法调用后被调用
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
BeanPostProcessor 是在我们bean进行初始化前后进行工作;
它是在getBean()后对bean进行初始化前后进行调用;
7. spring mvc 启动过程
- 创建一个servletContext 容器,将我们 Rootconfig保存到容器中;
- 创建一个contextLoaderListener, 注册到 servletContext中;
- 创建一个空的子容器,将webConfig,保存到中,setParent(servletContext),将servletContext作为父容器;
- 创建一个dispatcherServlet,并将其注册到子容器中
- contextLoaderListener,和 dispatcherServlet会进行刷新容器,将bean加载到我们容器中;
8. 容器刷新,创建Bean的过程
spring 容器启动流程:
- 刷新容器,标记容器启动
- 将配置信息解析,注册到BeanFactory
- 实例化BeanFactoryPostProcessor,调用beanFactoryPostProcessor修改bean definition
- 注册 beanpostprocessors
- 初始化当前的事件广播器
- 初始化所有非懒加载单例 singleton beans(lazy-init 的除外)
7.初始化容器的生命周期事件处理器,并发布容器的生命周期事件
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前准备工作
prepareRefresh();
// 调用子类refreshBeanFactory()方法,获取bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 创建bean Factory的通用设置
prepareBeanFactory(beanFactory);
try {
// 子类特殊的bean factory设置
postProcessBeanFactory(beanFactory);
// 实例化beanFactoryPostProcessor
// 调用beanFactoryPostProcessor修改bean definition
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 bean pst processors
registerBeanPostProcessors(beanFactory);
// 初始化信息源,和国际化相关
initMessageSource();
// 初始化容器事件传播器
initApplicationEventMulticaster();
// 调用子类特殊的刷新逻辑
onRefresh();
// 为事件传播器注册事件监听器
registerListeners();
// 实例化所有非懒加载单例
finishBeanFactoryInitialization(beanFactory);
// 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
// ...
}
finally {
// ...
}
}
}
9. springBean 的生命周期
bean 的生命周期指的是getBean后的生命周期;
spring bean 容器的生命周期流程如下:
- Spring 容器根据配置中的 bean 定义中实例化 bean。 2. Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
- 如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。
- 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
- 如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
- 如果为 bean 指定了 init 方法(<bean> 的 init-method 属性),那么将调用它。
- 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。 8. bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
- 如果为 bean 指定了 destroy 方法(<bean> 的 destroy-method 属性),那么将调用它
DI大概是这样的,根据我们要获取的BeanName,去IOC容器中找到对应的class,然后实例化出一个代理类对象,然后给这个对象的属性赋值。
10. 展开具体DI依赖注入过程
- 获取bean 的name,如果是别名将其转换
- 从缓存中取得单利bean
- 缓存中没有单利bean,判断是否可以在当前BeanFactory中获取单利bean,否则委托当前容器的父容器去寻找,按名字和类型
- 没有的话,创建bean
3.1 判断是不是原型实例,如果是,则抛出创建失败异常,如果不是,下一步。
3.2 检查 BeanDefinition 是否在当前的容器中,如果不在那可能在父类容器中,所以委托父类容器查找,如果还没有,则再上一级容器...递归查找。
3.3 检查这个实例是否是为了类型检查而获取,而不是用来使用,如果是,标记这个bean已经被创建,如果不是,下一步。
3.4 根据 beanName获取 父类的BeanDefinition,并检查该对象类类型,比如不能是抽象类等。
3.5 根据 beanName获取所有该 bean依赖的 Bean集合,如果该集合有值,则遍历DI(递归调用 getBean())该 bean集合里的bean,并把bean注册给当前的bean(维护了一个 map来存放关系)。
3.6 如果3.4中获取的 BeanDefinition是单例,则根据该单例对象和 beanName和 args创建一个实例对象;否则,判断 BeanDefinition是否是原型,如果是则根据 beanName,该对象, args创建一个实例;否则拿到3.4获取的 BeanDefinition对象的生命周期 Scope,然后根据 scope来创建实例对象,参数 (beanName,bd,args)。