文章目录
- 概览
- 对Spring的理解
- Spring启动流程
- Spring循环依赖与三级缓存
概览
Spring是一个轻量级的Java开源框架,为了解决企业应用开发的复杂性而创建的。Spring的核心是控制反转(IOC)和面向切面(AOP)。
简单来说,Spring是一个分层的JavaSE/EE 一站式轻量级开源框架。在每一层都提供支持。
- 表示层:spring mvc
- 业务层:spring
- 持久层:jdbctemplate、spring data
对Spring的理解
Spring是一个轻量级的框架,简化我们的开发,里面重点包含两个模块分别是IOC和AOP。
- IOC叫控制反转,在没用IOC之前都要手动new创建对象,使用IOC之后由容器进行对象的创建,并且由容器来管理对象,减去了开发上的成本,提高了工作效率。
- AOP叫面向切面编程,在实际项目开发中需要嵌入一些与业务不想关的代码的时候就可以使用AOP。比如,权限日志的增加。
Spring虽然把它当成框架来使用,但其本质是一个容器,即IOC容器,里面最核心是如何创建对象和管理对象,里面包含了Bean的生命周期和Spring的一些扩展点,包含对AOP的应用。
除此之外,Spring真正的强大之处在于其生态,它包含了Spring Framework、Spring Boot、Spring Cloud等一些列框架,极大提高了开发效率。
Spring启动流程
参考:https://blog.csdn.net/scjava/article/details/109587619
核心方法AbstractApplicationContext#refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// ...
}
finally {
// ...
}
}
}
- prepareRefresh 准备刷新容器,此方法做一些刷新容器的准备工作:
- 设置开启时间和对应标志位
- 获取环境对象
- 设置监听器和一些时间的集合对象
- obtainFreshBeanFactory 创建容器对象:DefaultListableBeanFactory;加载xml配置文件属性值到工厂中,最重要的是BeanDefinition
- prepareBeanFactory 完成bean工厂的某些初始化操作
- 设置BeanDefinition的类加载器
- 设置spring容器默认的类型转换器
- 设置spring解析el表达式的解析器
- 添加一个Bean的后置处理器ApplicationContextAwareProcessor
- 将bean工厂的一些类,比如ApplicationContext直接注册到单例池中
- 去除一些在byType或者byName的时候需要过滤掉的一些bean(spring在依赖注入的时候会先在这些默认注册的bean中进行byType找,如果找到了,就加入到列表中,简单来说就是比如你在bean中依赖注入了ApplicationContext context,那么spring会把默认注册的这些bean中找到然后进行注册)
- 将系统的环境信息、spring容器的启动环境信息、操作系统的环境信息直接注册成一个单例的bean
- postProcessBeanFactory 这里是一个空壳方法,spring目前还没有对他进行实现;这个方法是留给子类进行实现的,后续可以添加一些用户自定义的或者默认的一些特殊的后置处理器工程到beanFactory中去
- invokeBeanFactoryPostProcessors 调用后置处理器;将系统中所有符合条件的普通类都扫描成了一个BeanDefinition 并且放入到了beanDefinitionMap中,包括业务的bean,ban的后置处理器、bean工厂的后置处理器等等
- 将标记为容器单例类扫描成BeanDefinition放入BeanDefinition Map
- 处理@Import注解
- 如果我们的配置类是@Configuration的,那么会生成这个配置类的CGLIB代理类,如果没有加@Configuration,则就是一个普通Bean
- registerBeanPostProcessors 从beanDefinitionMap中取出bean的后置处理器然后放入到后置处理器的缓存列表中
- initMessageSource 初始化国际化资源信息
- initApplicationEventMulticaster 事件注册器初始化
- onRefresh 空壳方法,留给子类实现
- registerListeners 将容器中和BeanDefinitionMap中的监听器添加到事件监听器中
- finishBeanFactoryInitialization 创建单例池,将容器中非懒加载的Bean,单例bean创建对象放入单例池中,包括容器的依赖注入
- finishRefresh 容器启动过后,发布事件
Spring循环依赖与三级缓存
Spring循环依赖调用流程:
在BeanA中注入BeanB,BeanB中注入BeanA,在BeanA创建的过程中,会先判断容器中A是否存在,如果不存在会先初始化BeanA,然后给BeanA赋值,此时会给BeanA里的BeanB属性赋值,在赋值之前会将创建BeanA的流程放到三级缓存中(三级缓存为Map结构,key为String,value为函数式接口); 由于BeanA里面包含BeanB,所以接下来给BeanB执行创建流程,判断容器中是否存在BeanB,给属性B赋值,此时会给BeanB里的BeanA属性赋值。
在判断容器中是否存在该Bean时,查找顺序为:一级缓存->二级缓存->三级缓存,经历过上面的步骤后,此时三级缓存中A和B都有值(为BeanA、B的创建流程),不需要再进行初始化操作,然后将会执行BeanA的创建流程并将其放入二级缓存中并删除三级缓存中的值,但是此时BeanA中的BeanB还未赋值进行完全的初始化,
BeanA已经创建,此时会将BeanA赋值给BeanB中的A属性,至此BeanB已经完全赋值,然后将完全赋值的BeanB放入一级缓存中并删除三级缓存中的值,由于BeanB已经完全赋值,此时将其赋值给BeanA,将BeanA放入一级缓存并删除二级缓存,至此循环依赖问题解决。
Spring循环依赖大致调用思路:
- 第一次:A,容器是否存在?(一级缓存->二级缓存->三级缓存)初始化A,-> 将A的创建流程加入三级缓存 -> 给A赋值
- 第二次:B,容器中是否存在?(一级缓存->二级缓存->三级缓存)初始化B -> 将B的创建流程加入三级缓存 -> 给B赋值
- 第三次:A的三级缓存中有值,不需要进行初始化操作,执行创建A的流程,将其放入二级缓存,返回值给到创建B,此时B已经创建完全,将其加入一级缓存,然后将该返回值给到A,将A加入一级缓存,至此循环依赖问题解决。