简介
Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。
主要优势
- 方便解耦简化开发
- AOP编程支持
- 声明式事务
- 方便程序的测试
- 方便集成各种优秀框架
核心思想
在Spring中拥有许多的组件,但核心部分主要为:Beans、Core、Context、Expression,其中最为主的为Core、与Beans,它们提供了最为核心的IOC和依赖注入功能。
核心结构
框架设计理念:
在Spring框架中,其最核心组件应属Beans,Spring-Beans模块是所有应用都必须使用的,它包含了访问配置文件、创建和管理Bean以及进行控制反转(IOC,Inversion of Control)、依赖注入(DI,Dependency Injection)操作相关的所有类。Spring是面向Bean编程,Bean 在 Spring 中才是真正的主角。
IOC
IOC,Inversion of Control (控制反转/反转控制),注意它是⼀个技术思想,不是⼀个技术实现。
为什么叫做控制反转?
- 控制:指的是对象创建(实例化、管理)的权利
- 反转:控制权交给外部环境了(spring框架、IoC容器)
IOC解决什么问题?
解决对象之间的耦合问题。
IOC 与 DI 的区别?
DI:Dependancy Injection(依赖注⼊),IOC和DI描述的是同⼀件事情,只是理解角度不一样。
初始化主体流程
Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容。
BeanFactory 容器继承体系如下图
Spring IOC 容器初始化的关键环节在 AbstractApplicationContext#refresh() ⽅法中,如下所示
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 第⼀步:刷新前的预处理
prepareRefresh();
/*
第⼆步:
获取BeanFactory;默认实现是DefaultListableBeanFactory
加载BeanDefition 并注册到 BeanDefitionRegistry
*/
ConfigurableListableBeanFactory beanFactory =
obtainFreshBeanFactory();
// 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加
载器等)
prepareBeanFactory(beanFactory);
try {
// 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
postProcessBeanFactory(beanFactory);
// 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执
⾏
registerBeanPostProcessors(beanFactory);
// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
initMessageSource();
// 第⼋步:初始化事件派发器
initApplicationEventMulticaster();
// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
onRefresh();
// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器
bean
registerListeners();
/*
第⼗⼀步:
初始化所有剩下的⾮懒加载的单例bean
初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
填充属性
初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
*/
finishBeanFactoryInitialization(beanFactory);
/*
第⼗⼆步:
完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
件 (ContextRefreshedEvent)
*/
finishRefresh();
}
......
}
}
循环依赖
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。
Spring中循环依赖场景有:
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)
处理机制
- 单例 bean 构造器参数循环依赖(⽆法解决)
- prototype 原型 bean循环依赖(⽆法解决)
- 单例bean通过setXxx或者@Autowired进⾏循环依赖
三级缓存
首先看下Spring创建一个bean的基本流程:
创建该实例的原始对象 --> 进行自动装配 --> AOP代理处理 --> 完成bean的创建并加入单例池(即一级缓存)
但是当有循环依赖的时候,Spring是如何解决的呢?
主要原理是利用三级缓存机制:
- singletonObjects: 一级缓存,也就是我们平常理解的单例池。
- singletonFactories: 二级缓存,存储的是单例工厂。
- earlySingletonObjects: 三级缓存,存储正在创建中的单例对象。
为什么要设立三级缓存呢?
其实当不需要实现AOP的时候,解决循环依赖不用三级缓存机制,也不用单例工厂,二级缓存就足以实现。
第一级:singletonObjects
第二级:earlySingletonObjects
不需要实现AOP时Spring解决循环依赖基本流程:
假设单例一与单例二相互依赖对方并且此时都没有加入到单例池
- 创建单例一
- 将单例一加入earlySingletonObjects缓存
- 自动装配单例二
- 判断单例二在earlySingletonObjects缓存是否存在
- 不存在则创建单例二
- 将单例二并且加入earlySingletonObjects缓存
- 自动装配单例一
- 判断单例一在earlySingletonObjects缓存是否存在
- 明显第2步已经加入earlySingletonObjects缓存
- 注入成功,单例2创建完成并加入singletonObjects单例池
- 注入成功,单例1创建完成并加入singletonObjects单例池
那为什么要设立三级缓存呢?
这是因为当需要使用AOP时,将会对原始对象进行代理,因此最后的对象将是代理对象而不是原始对象。
所以按照二级缓存的步骤进行创建的话将会造成一个问题:
第2步加入到二级缓存中的对象是原始对象,导致第7步自动装配到到单例2中的单例1对象是原始对象,这个对象还没有完成AOP的处理。如果此时完成单例2的创建,之后在完成进行单例1的创建时,单例1对原始对象进行AOP处理,将导致最终的单例1对象不是之前自动装配到单例2中的单例1对象。
Spring选择使用三级缓存来解决这个问题:singletonFactories缓存中的对象是一个单例工厂,该工厂可以将原始对象进行AOP处理。
- singletonObjects: 一级缓存,也就是我们平常理解的单例池。
- singletonFactories: 二级缓存,存储的是单例工厂。
- earlySingletonObjects: 三级缓存,存储正在创建中的单例对象。
获取三级缓存的核心代码如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
getSingleton方法的大概处理过程为:
- 判断singletonObjects单例池中是否存在,存在则返回
- 不存在则判断earlySingletonObjects缓存中是否存在,存在则返回
- 不存在则判断singletonFactories缓存中是否存在,不存在则返回null
- 存在则通过该存储工厂创建出最终的bean
- 将该bean加入earlySingletonObjects缓存并从singletonFactories缓存中中移除
存在三级缓存机制下处理流程如下:
假设单例1与单例2相互依赖对方并且此时都没有加入到单例池
- 创建单例一
- 创建单例一的工厂对象并且加入singletonFactories缓存
- 自动装配单例二
- 通过 getSingleton方法 判断单例二在三级缓存中是否存在
- 明显此时单例一不存在,所以创建单例二
- 创建单例二的工厂并且加入singletonFactories缓存
- 自动装配单例一
- 通过 getSingleton方法 判断单例一在三级缓存中是否存在
- 明显第2步已经加入singletonFactories缓存
- 单例二进行AOP处理
- 注入单例一成功,单例二创建完成并加入singletonObjects单例池
- 注入单例二成功,单例一创建完成并加入singletonObjects单例池
三级缓存的好处:
- 通过单例工厂创建可以实现AOP创建最终对象
- 加入earlySingletonObjects缓存不用每次都通过工厂创建
AOP
Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程,AOP是OOP的延续
OOP编程思想可以解决⼤多数的代码重复问题,但是有⼀些情况是处理不了的,⽐如下⾯的在顶级⽗类
Animal中的多个⽅法中相同位置出现了重复代码,OOP就解决不了。
AOP提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离。
解决什么问题?
在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。
默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术,不过可以通过配置的⽅式,让Spring强制使⽤CGLIB。
Bean的生命周期
在Spring中,Bean默认为单例模式,可以设置为多例。一个Bean从创建到销毁,大致经历以下步骤:
- 实例化Bean,根据Spring配置,执行包扫描操作,并对其进行实例化操作。
- 根据Spring上线文对实例化的Bean进行配置,其中包括依赖注入。
- 判断是否实现了BeanNameAware接口,如果有会执行setBeanName方法去设置这个Bean的id,即自己设置Bean在BeanFactory中的名字。
- 判断是否实现了BeanFactoryAware接口,如果有则执行setBeanFactory方法,使得Bean可以获取自己的工厂,从而可以使用工厂的getBean方法。
- 判断是否实现了ApplicationContextAware接口,如果有则执行setApplicationContext方法,使得在Bean中可以获取Spring上下文,从而可以获取通过上下文去getBean,该步骤与上一步作用大致相同,但通过该中方式能实现的功能却更加丰富。
- 判断是否实现了BeanPostProcessor接口,如果有则调用postProcessBeforeInitialization方法,这一步属于实例化Bean的前置操作,在经过该步骤后,即Bean实例化后同样也会执行一个操作。
- 判断Bean是否配置了init-method,如果有,在Bean初始化之后会默认执行一次init-method指定的方法。
- 判断Bean是否实现了BeanPostProcessor接口,如果有则调用postProcessAfterInitialization方法,该方法属于Bean实例化后的操作。在经过这个步骤后,Bean的初始化操作就完成了。
- 当Bean实例化完成后,当Bean不再被需要的时候会执行销毁操作。一般是在ApplicationContext执行close方法时会进行销毁操作。
- 在销毁过程中,判断是否实现了DisposableBean接口,如果有则执行destroy方法。
- 判断Bean是否配置了destroy-method,如果有,在销毁过程中会默认执行一次destroy-method方法。
BeanFactory与ApplicationContext区别
BeanFactory是Spring框架中IoC容器的顶层接⼝,只是⽤来定义⼀些基础功能,定义⼀些基础规范,⽽
ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的。 通常称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,⽐BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等。
FactoryBean 和 BeanFactory
BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚, 具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext。Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成某⼀个类型的Bean实例,可以借助它⾃定义Bean的创建过程。
后置处理器
Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使⽤上是有所区别的。 ⼯⼚初始化(BeanFactory)—> Bean对象
在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理做⼀些事情
在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情。
Bean初始化过程
Spring初始化过程中最后执行的核心方法是AbstractRefreshableApplicationContext类的refresh方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1.为应用上下文的刷新做准备--设置时间、记录刷新日志、初始化属性源中的占位符(事实上什么都没做)和验证必要的属性等
// Prepare this context for refreshing.
prepareRefresh();
// 2.让子类刷新内部的bean factory
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//3.为上下文准备bean factory
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 4.bean factory 后置处理
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// 5.调用应用上下文中作为bean注册的工厂处理器
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 6.注册拦截创建bean的bean处理器
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 7.初始化消息源
// Initialize message source for this context.
initMessageSource();
// 8.初始化事件广播
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 9.初始化特定上下文子类中的其它bean
// Initialize other special beans in specific context subclasses.
onRefresh();
// 10.注册监听器bean
// Check for listener beans and register them.
registerListeners();
// 11.实例化所有的单例bean
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// 12.发布相应的事件
// Last step: publish corresponding event.
finishRefresh();
}catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
//销毁错误的资源
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
//重置刷新标志
// Reset 'active' flag.
cancelRefresh(ex);
//主动抛出异常
// Propagate exception to caller.
throw ex;
}
finally {
//重置内存缓存
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
通过源码可以看出该方法是构建整个IOC容器的完成过程。其中每一行代码都是创建容器的一个流程。其中主要包括以下几个步骤:
- 构建BeanFactory
- 添加事件处理
- 创建 Bean 实例对象并构建Bean关系
- 触发被监听的事件
构建BeanFactory
在第二步中,obtainFreshBeanFactory方法主要调用了AbstractRefreshableApplicationContext#refreshBeanFactory方法:
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
以上是BeanFactory的创建过程,首先判断当前容器是否存在BeanFactory,如果有则销毁后在进行创建。BeanFactory的是DefaultListableBeanFactory的实例对象,类图如下:
从这个图中发现除了 BeanFactory 相关的类外,还发现了与 Bean 的 register 相关。这在 refreshBeanFactory 方法中有一行 loadBeanDefinitions(beanFactory) 这个方法将开始加载、解析 Bean 的定义,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构。对于WEB应用而言,其调用的是XmlWebApplicationContext#loadBeanDefinitions方法。在BeanFactory创建成功后,Spring将创建的对象交于第三步,即prepareBeanFactory方法为其添加一些 Spring 本身需要的一些工具类。
添加事件处理
在第4、5、6步中,这三行代码对 Spring 的功能扩展性起了至关重要的作用 。其中第4、5步的代码主要是让你可以在Bean已经被创建,但未被初始化之前对已经构建的 BeanFactory 的配置做修改;第6步代码主要是让你可以对以后再创建 Bean 的实例对象时添加一些自定义的操作 。
第4步,即postProcessBeanFactory方法。主要功能为允许上下文能对BeanFactory做一些处理。比如:AbstractRefreshableWebApplicationContext抽象类实现了该方法,并在方法中对Servlet做了一些处理。
第5步,即invokeBeanFactoryPostProcessors方法主要是获取实现 BeanFactoryPostProcessor 接口的子类。其中主要包括执行BeanDefinitionRegistryPostProcessor类型的postProcessBeanDefinitionRegistry方法,以及执行非BeanDefinitionRegistryPostProcessor类型的postProcessBeanFactory方法。当然,该方法传入的参数是ConfigurableListableBeanFactory 类型,我们仅能对BeanFactory的一些配置做修改。
第6步,即registerBeanPostProcessors 方法也是可以获取用户定义的实现了 BeanPostProcessor 接口的子类,并执行把它们注册到 BeanFactory 对象中的 beanPostProcessors 变量中。BeanPostProcessor 中声明了两个方法:postProcessBeforeInitialization、postProcessAfterInitialization 分别用于在 Bean 对象初始化时执行。可以执行用户自定义的操作。
第7、8、9、10步的方法主要是初始化监听事件和对系统的其他监听者的注册,监听者必须是 ApplicationListener 的子类。 在容器启动时,Spring会调用ApplicationStartListener的onApplicationEvent方法。
创建 Bean 实例对象并构建Bean关系
Bean的实例化过程是第11步开始的,即finishBeanFactoryInitialization方法,而在finishBeanFactoryInitialization方法中核心方法又为preInstantiateSingletons(DefaultListableBeanFactory类)。在该方法中,首先拿到所有beanName,然后在实例化的时候会判断bean是否为FactoryBean,顾名思义,这是一个特殊的工厂Bean,可以产生Bean的Bean。
这里的产生 Bean 是指 Bean 的实例,如果一个类继承 FactoryBean 用户只要实现他的 getObject 方法,就可以自己定义产生实例对象的方法。然而在 Spring 内部这个 Bean 的实例对象是 FactoryBean,通过调用这个对象的 getObject 方法就能获取用户自定义产生的对象,从而为 Spring 提供了很好的扩展性。Spring 获取 FactoryBean 本身的对象是在前面加上 & 来完成的。
在Bean的实例化主要分两个步骤:
-
Bean不为抽象、单例、非懒加载。
判断Bean是否为FactoryBean,是则执行FactoryBean相关的操作,否则直接调用getBean方法产生实例。
-
在singleton的bean初始化完了之后调用SmartInitializingSingleton的afterSingletonsInstantiated方法。
通过跟进Bean实例化代码可以发现getBean方法最后指向的是AbstractBeanFactory类的抽象方法createBean,其实现类为AbstractAutowireCapableBeanFactory。在该方法中有一个步骤会去查找Bean的依赖关系,并对其进行依赖注入操作。这里画一个时序图来作说明。
在resolveValueIfNecessary方法中,不仅有调用resolveReference,同样的还有resolveInnerBean,即解析内部的Bean引用。
触发被监听的事件
在经历第11步后,上下文的创建就已经基本完成了,这时Spring会执行finishRefresh方法,完成此上下文的刷新。其中包括LifecycleProcessor的onRefresh方法,并执行ContextRefreshedEvent事件。例如:执行SpringMVC的事件。
总结
在Bean声明周期中曾讲到,Spring在初始化Bean的时候先后对调用BeanPostProcessor接口的postProcessBeforeInitialization、postProcessAfterInitialization方法。利用这一特性我们可以在Bean中实现BeanPostProcessor接口,然后再方法体中加入自己的逻辑。
对于Spring的IOC容器而言,除了BeanPostProcessor,还有BeanFactoryPostProcessor。BeanFactoryPostProcessor是在构建BeanFactory和构建Bean对象时调用。IOC容器允许BeanFactoryPostProcessor在容器初始化任何Bean之前对BeanFactory配置进行修改。
在Spring的IOC容器中还有一个特殊的Bean,即FactoryBean,FactoryBean主要用于初始化其他Bean,我们可以自己实现一个FactoryBean,然后添加自定义实例化逻辑。在Spring中,AOP、ORM、事务管理等都是依靠FactoryBean的扩展来实现的。
笔记不易,喜欢就关注一下我以及我的公众号吧!