一、简介
SpringIOC解决的问题:将对象之间的关系使用配置或者注解管理
Bean是Spring的一等公民:
-
Bean的本质就是Java对象,只是这个对象的生命周期由容器管理,只需要告诉Spring它需要管理哪些对象
-
不需要为了创建Bean而在原来的Java类上添加任意的限制,体现了代码的低侵入
-
对Java对象的配置体现在配置文件或者注解上
BeanDefinition
-
在Java中曾经使用的Class对象来描述,在Spring中描述Bean的定义
-
主要配置额外属性:
-
作用范围scope(@Scope),有五个,最重要的是singleton和prototype
-
懒加载lazi-init(@Lazy):决定Bean是否延迟加载,如果为true,则只有在使用的时候才会创建
-
首选primary(@Primary):如果存在一个接口对应多个实现,设置为true的Bean会被优先装配
-
工厂类Beanfactory-bean(@Configuration)和工厂方法Beanfactory-method(@Bean):指示出Bean在哪个类的什么方法创建
-
Spring中Bean的继承关系是通过parent属性定义
二、IOC容器
1. 简单容器接口BeanFactory
BeanFactory接口的核心方法:
- getBean:可以通过Bean的名字或者Class对象获取Bean的实例
- isSingleton和isPrototype:判断是否是单例
- getType:根据名字获取Class对象
- getAliases:根据Bean的名字获取它的别名数组
BeanFactory和FactoryBean的区别?
-
BeanFactory是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。
-
在Spring中,BeanFactory是IoC容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
-
Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最常用的一个。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
-
当一个受Spring容器管理的bean 如果实现了FactoryBean接口 在bean实例化(getBean)阶段 Spring会调用该bean的getObejct方法返回的不一定是自身的实例,对bean的生产修饰做了很好的封装。
-
如果想要获取FactoryBean的实现类,在名字前面加“&”
FactoryBean举例
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
Object bean = applicationContext.getBean("&factory");
System.out.println(bean);
Object bean2 = applicationContext.getBean("factory");
System.out.println(bean2);
}
output:
com.imooc.entity.factory.factory@3bbc39f8
com.imooc.entity.User@4ae3c1cd
2. ListableBeanFactory接口
-
负责批量列举容器Bean的信息
核心方法:
-
getBeanDefinitionNames():可以列出IOC容器的加载的Bean的名字
-
getBeanDefinitionCount():获取容器中Bean的数目
3. AutowireCapableBeanFactory接口
- 负责自动依赖注入
自动装配策略有:
- 根据名称
- 根据类型
- 根据构造函数
- 不自动装配
比如@Autowire方法调用的就是resolveDependency()实现的自动注入,使用的是根据类型进行依赖注入,@Resource和@Qualifier按名称匹配注入Bean
4. DefaultListableBeanFactory类
- 第一个具备IOC容器的实现类
- 提供了beanDefinitionMap负责记录Bean的定义
/** Map of bean definition objects, keyed by bean name. */
//记录Bean的注册信息
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
5. 高级容器接口ApplicationContext
继承了多个接口,提供了丰富的功能:
- EnvironmentCapable:提供加载多个配置文件的能力
- ListableBeanFactory:通过列表的方式管理Bean
- HierarchicalBeanFactory:支持多层级的容器,提供对每一个层级Bean的管理
- ResourcePatternResolver:可以用于加载资源文件
- ApplicationEventPublisher:具备事件发布的能力
基于传统XML配置的实现类:
- **FileSystemXmlApplicationContext:**从文件系统加载并定义相关资源
- **ClassPathXmlApplicationContext:**从classpath加载配置
- **XmlWebApplicationContext:**用于Web应用程序
流行的根据注解的实现类
-
**AnnotationConfigApplicationContext:**负责非Web应用
-
**AnnotationConfigServletWebServerApplicationContext:**负责Web的应用
-
**AnnotationConfigReactiveWebServerApplicationContext:**额外满足响应式的需求
6. ConfigurableApplicationContext接口
- 是ApplicationContext的子接口
- 继承了Lifecycle接口,提供控制IOC容器生命周期的方法
- 提供了refresh方法,初始化容器,也可以重新启动容器
7. AbstractApplicationContext
是一个模板方法的一个体现
- refresh,属于模板方法,定义了容器初始化的算法骨架
- prepareRefresh,是一个具体的方法,由这个抽象类本身实现
- postProcessBeanFactory是一个钩子方法,子类可以根据情况选择是否实现
- refreshBeanFactory是一个抽象方法,强制子类实现
三、容器初始化
主要处理逻辑是AbstractApplicationContext的Refresh()方法,这是个模板方法,定义了容器初始化的算法,应用了模板设计模式,所以这个类也是个抽象类。
1. 后置处理器post processor
有三种后置处理器:
-
BeanDefinition后置处理器,继承了BeanFactory后置处理器,用于处理BeanDefinition,也可以处理容器
-
BeanFactory后置处理器,用于处理容器
-
Bean的后置处理器,用于处理Bean
作用:
- 本身也是需要注册到容器中的Bean
- 定义一些方法,这些方法会在特定的时机被容器所调用
- 实现不改变容器或者Bean核心逻辑的情况下对容器或者Bean进行扩展
- 比如对一些方法进行包装,修改内容等
BeanDefinitionPostProcessor举例
- Mybatis就会搜索第三方Jar包中的Class,将其注入到IOC容器中
BeanPostProcessor举例
- 有两个方法分别负责Bean初始化前做什么事情,初始化后做什么事情,但是需要定义一个过滤规则,对不同的bean进行过滤
2. Aware接口
- bean实现xxxAware接口可以感知到容器
- 可以获取容器BeanFactory(低级容器)、ApplicationContext(高级容器)、BeanName(bean的名字)、ResourceLoader(资源加载器)
3. 事件监听者模式
Spring中的事件驱动模型
- 事件:ApplicationEvent抽象类是Spring中所有事件的父类,比如对于容器事件定义了一个ApplicationContextEvent子类,该子类有几个子类,比如容器关闭后的事件、容器启动时的事件、容器初始化完成后的事件
- 事件监听器:ApplicationListener接口,该接口的两个子接口都有两个方法,判断当前事件源以及事件是否是该监听器感兴趣的,开发者可以继承父接口或者在某个Bean方法上使用注解@EventListener
- 事件发布器:ApplicationEventPublisher以及ApplicationEventMulticaster接口。ApplicationEventPublisher提供事件发布的能力,ApplicationContext实现了该接口,也就是说高级的IOC容器具备发布事件的能力,可以在bean实现对应的Aware接口,获取容器的发布器。ApplicationEventMulticaster提供了注册和删除监听器的能力,利用Set集合保存监听器,默认的子实现类在定义了Executor,也就是可以通过多线程使用异步的方式调用注册好的监听器
详情见:
4. 容器刷新逻辑
-
调用prepareRefresh():负责做刷新前的准备工作
- 设置刷新时间
- 设置容器的状态为激活
- 创建事件集合
-
obtainFreshBeanFactory():获取容器刷新后的BeanFactory实例,会进行BeanDefinition的注册
-
prepareBeanFactory(beanFactory):为容器注册一些系统级别的Bean
-
设置表达式语言处理器、资源加载器、事件发布器
-
设置动态装配规则
-
判断是否需要织入器,使用Bean级别的后置处理器进行AOP操作
-
添加后置处理器将容器传递给实现ApplicationContextAware接口的Bean、如果某个 bean实现了Aware接口,将在自动装配的时候忽略它们
-
postProcessBeanFactory(beanFactory):注册容器级别的后置处理器
-
invokeBeanFactoryPostProcessors(beanFactory):调用容器级别的后置处理器
-
registerBeanPostProcessors(beanFactory):注册Bean级别的后置处理器,在类初始化前和初始化后进行一些处理
-
initMessageSource():初始化国际化的配置
-
initApplicationEventMulticaster():初始化事件发布者组件,支持事件的发布和注册
-
onRefresh():提供提前初始化一些特殊的Bean
-
registerListeners():注册事件监听器
-
finishBeanFactoryInitialization(beanFactory):主要实例化所有不是懒加载的实例
-
解析相关配置文件的值,如@Value注解
-
进行类编译器的AOP织入操作
-
先实例化所有不是懒加载的实例,通过BeanDefinition判断Bean是否是抽象的、单例的和懒加载的
-
AOP分为三种方式:编译期织入、类加载期织入和运行期织入
-
finishRefresh():触发初始化完成的回调方法,发布容器刷新完成的事件给监听者
-
resetCommonCaches():重启共用缓存
refresh源码
/**
* 加载或刷新一个持久化的配置,可能是XML文件、属性文件或关系数据库模式。
* 由于这是一种启动方法,如果失败,应该销毁已经创建的单例,以避免悬空资源。
* 换句话说,在调用该方法之后,要么全部实例化,要么完全不实例化。
* @throws 如果bean工厂无法初始化,则抛出 BeansException 异常
* @throws 如果已经初始化且不支持多次刷新,则会抛出 IllegalStateException 异常
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
// 给容器refresh加锁,避免容器处在refresh阶段时,容器进行了初始化或者销毁的操作
synchronized (this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识,具体方法
prepareRefresh();
//告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
//子类的refreshBeanFactory()方法启动,里面有抽象方法
//针对xml配置,最终创建内部容器,该容器负责 Bean 的创建与管理,此步会进行BeanDefinition的注册
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册一些容器中需要的系统Bean.例如classloader,beanfactoryPostProcessor等
prepareBeanFactory(beanFactory);
try {
//允许容器的子类去注册postProcessor ,钩子方法
postProcessBeanFactory(beanFactory);
// 激活在容器中注册为bean的BeanFactoryPostProcessors
//对于注解容器,org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
//方法扫描应用中所有BeanDefinition并注册到容器之中
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建过程的BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 找到“messageSource”的Bean提供给ApplicationContext使用,
// 使得ApplicationContext具有国际化能力。
initMessageSource();
// 初始化ApplicationEventMulticaster该类作为事件发布者,
// 可以存储所有事件监听者信息,并根据不同的事件,通知不同的事件监听者。
initApplicationEventMulticaster();
// 预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,
// 该方法需要在所有单例 bean 初始化之前调用
// 比如Web容器就会去初始化一些和主题展示相关的Bean(ThemeSource)
onRefresh();
// 注册监听器(检查监听器的bean并注册它们)
registerListeners();
//设置自定义的类型转化器ConversionService,
// 设置自定义AOP相关的类LoadTimeWeaverAware,
// 清除临时的ClassLoader
// ,实例化所有的类(懒加载的类除外)
finishBeanFactoryInitialization(beanFactory);
// 初始化容器的生命周期事件处理器,(默认使用DefaultLifecycleProcessor),调用扩展了SmartLifecycle接口的start方法
// 当Spring容器加载所有bean并完成初始化之后,会接着回调实现该接口的类中对应的方法(start()方法)
// 并发布容器刷新完毕事件ContextRefreshedEvent给对应的事件监听者
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.
//销毁已创建的Bean
destroyBeans();
// Reset 'active' flag.
//取消refresh操作,重置容器的同步标识
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// 重置Spring内核中的共用的缓存,因为我们可能再也不需要单例bean的元数据了……
resetCommonCaches();
}
}
}
四、容器获取Bean
主要了解的是@Autowired注解的,使用类型的注入方式。
方法递归调用顺序:
- getBean()
- dogetBean()
- getSingleton():从缓存中获取
- createBeanInstance():创建未赋值的Bean实例
- addSingletonFactory():为了防止循环引用,将对象引用放入三级缓存
- populateBean:进行依赖注入
1. getBean
是AbstractAutowireCapableBeanFactory的getBean方法,真正工作的是doGetBean方法
核心逻辑:
- 将GetBean方法传入的名字进行处理,比如是不是用&符号打头,以及尝试从别名集合中获取真正的名字,可能会出现获取到的依然是别名,所以就会递归查询,直到查询不出别名
- 根据Bean的名字,尝试从缓存中获取单例Bean实例,可能是单例Bean或者FactoryBean本身,如果存在Bean实例直接返回,或者存在FactoryBean,会调用getObject方法返回Bean实例
- 循环依赖判断,就是A中存在属性B,B中存在属性A,就出现了循环的依赖问题,即A的创建依赖于B的创建,B的创建依赖于A的创建
- 递归去父容器获取BeanDefinition实例,最后会合并子类和父类的BeanDefinition,防止出现BeanDefinition过期的情况
- 递归实例化显示依赖的Bean,如果A中的depends-on属性指向B,则B要先被实例化,依赖关系会注册到Set中,保存了A依赖哪些以及哪些依赖A。如果人为定义的属性出现循环依赖,则会直接出现异常,因为Spring框架,认为这个创建顺序是必须要严格遵守的
- 根据不同的Scope采用不同的策略创建Bean,最后放入到一级缓存中,并将二级三级缓存清除,并且注册在Bean创建成功列表
- 对Bean进行类型检查
FactoryBean和ObjectBean的区别?
-
ObjectBean功能和FactoryBean类似,但是为了区别用户自定义的和框架自己使用的,采用了两套名字
-
框架使用ObjectBean接口的不同实现类,会产生不同Scope的实例对象
2. 单例的三级缓存
- 先从singletonObjects这个一级缓存获取,主要包含最终形态的Bean实例
- 如果一级缓存没有获取到,就会给一级缓存加锁,从二级缓存获取,也就是earlySingletonObjects,因为前面已经加锁,所以二级缓存以及三级缓存都是采用的HashMap来提升性能,二级缓存是早期的bean实例,还没有给属性赋值
- 如果二级缓存没有获取到,就会从三级缓存获取,也就是singletonFactorys中获取,这里面存储的是ObjectBean,类似于FactoryBean。如果此时获取到,就会调用getObject方法,存入二级缓存,然后删除三级缓存,防止重复创建
3. 如何判断是否是循环依赖?
-
创建一个Bean时,就会记录在一个列表中,单例模式会记录在Set集合中,而原型模式会记录在一个ThreadLocal中,确保一个线程创建一个
-
如果A依赖B,就会先创建B,B此时依赖A,就会再创建A,发现A正在被创建,就认为有循环依赖,防止doGetBean递归调用
-
支持单例模式的循环依赖
-
对原型模式,如果判断到循环依赖,就会抛出异常,是不支持的
源码:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//尝试从一级缓存里面获取完备的Bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果完备的单例还没有创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
//因此看看是否正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//尝试给一级缓存对象加锁,因为接下来就要对缓存对象操作了
synchronized (this.singletonObjects) {
//尝试从二级缓存earlySingletonObjects这个存储还没进行属性添加操作的Bean实例缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
//如果还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
if (singletonObject == null && allowEarlyReference) {
//从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//如果获取到工厂实例
if (singletonFactory != null) {
//调用单例工厂的getObject方法返回对象实例
singletonObject = singletonFactory.getObject();
//将实例放入二级缓存里
this.earlySingletonObjects.put(beanName, singletonObject);
//从三级缓存里移除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
4. doGetBean源代码
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//通过三种形式获取beanName
// 一个是原始的beanName,一个是加了&的,一个是别名
final String beanName = transformedBeanName(name);
Object bean;
// 尝试从单例缓存集合里获取bean实例
Object sharedInstance = getSingleton(beanName);
//如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空
//则执行if里面的逻辑
//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
//如果Bean还在创建中,则说明是循环引用
if (isSingletonCurrentlyInCreation(beanName)) {
//...
}
}
// 如果是普通bean,直接返回,如果是FactoryBean,则返回他的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//若scope为prototype或者单例模式但是缓存中还不存在bean
else {
//如果scope为prototype并且显示还在创建中,则基本是循环依赖的情况
//针对prototype的循环依赖,spring无解,直接抛出异常
// A->B->A
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 从当前容器中找不到指定名称的bean,此时递归去parentFactory查找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 主要针对FactoryBean,将Bean的&重新加上
String nameToLookup = originalBeanName(name);
//如果parent容器依旧是AbstractBeanFactory的实例
//instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例
if (parentBeanFactory instanceof AbstractBeanFactory) {
//直接递归调用方法来查找
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
//....
}
//typeCheckOnly 是用来判断调用 getBean() 是否仅仅是为了类型检查获取 bean,而不是为了创建Bean
if (!typeCheckOnly) {
// 如果不是仅仅做类型检查则是创建bean
markBeanAsCreated(beanName);
}
try {
//将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//对合并的BeanDefinition做验证,主要看属性是否为abstract的
checkMergedBeanDefinition(mbd, beanName, args);
// 获取当前Bean所有依赖Bean的名称
String[] dependsOn = mbd.getDependsOn();
// 如果当前Bean设置了dependsOn的属性
//depends-on用来指定Bean初始化及销毁时的顺序
//<bean id=a Class="com.imooc.A" depends-on="b" />
// <bean id=b Class="com.imooc.B" />
if (dependsOn != null) {
for (String dep : dependsOn) {
//校验该依赖是否已经注册给当前 bean,注意这里传入的key是当前的bean名称
//这里主要是判断是否有以下这种类型的依赖:
//<bean id="beanA" class="BeanA" depends-on="beanB">
//<bean id="beanB" class="BeanB" depends-on="beanA">
//如果有,则直接抛出异常
if (isDependent(beanName, dep)) {
//...
}
//缓存依赖调用,注意这里传入的key是被依赖的bean名称
registerDependentBean(dep, beanName);
//递归调用getBean方法,注册Bean之间的依赖(如C需要晚于B初始化,而B需要晚于A初始化
// 初始化依赖的bean
getBean(dep);
}
}
//如果BeanDefinition为单例
if (mbd.isSingleton()) {
//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 显式从单例缓存中删除 bean 实例
// 因为单例模式下为了解决循环依赖,可能它已经存在了,所以将其销毁
destroySingleton(beanName);
throw ex;
}
});
// 如果是普通bean,直接返回,是FactoryBean,返回他的getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
//Prototype每次都会创建一个新的对象
Object prototypeInstance = null;
//默认的功能是注册当前创建的prototype对象为正在创建中
beforePrototypeCreation(beanName);
//创建原型对象实例
prototypeInstance = createBean(beanName, mbd, args);
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//要创建的Bean既不是单态模式,也不是原型模式,则根据Bean定义资源中
//配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中
//比较常用,如:request、session、application等生命周期
}
//对创建的Bean实例对象进行类型检查
if (requiredType != null && !requiredType.isInstance(bean)) {
//....
}
return (T) bean;
}
六、容器创建Bean
这个是doGetBean方法里面的CreatBean
1. 创建前的准备
AbstractAutowireCapableBeanFactory类的createBean方法
- Bean类型的解析,主要是解析获取Class对象
- 处理方法覆盖,比如说lookup-method属性以及replaced-method属性指定的Bean中是否有这些方法,以及是否出现方法的重载,否则还需要对方法进行处理
- 做Bean实例化前的后置处理
- 最后调用doCreatBean方法进行创建
源码:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
//克隆一份BeanDefinition,用来设置上加载出来的class对象
//之所以后续用该副本操作,是因为不希望将解析的class绑定到缓存里的BeanDefinition
//因为class有可能是每次都需要动态解析出来的
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//校验和准备Bean中的方法覆盖
mbdToUse.prepareMethodOverrides();
//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
//resolveBeforeInstantiation只是针对有自定义的targetsource,
// 因为自定义的targetsource不是spring的bean那么肯定不需要进行后续的一系列的实例化,初始化。
// 所以可以在resolveBeforeInstantiation直接进行proxy
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
//创建Bean的入口
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
2. doCreatBean
-
通过工厂方法比如说factory-method方法,或者使用无参构造器注入以及含参构造器注入最终创建一个无属性的Bean实例,在这一步会判断是否需要利用CGLIB替换方法
-
执行Bean实例化后的后置处理器,其中包含记录被@Autowired或者@Value方法标记的属性或者方法实例,便于后续的依赖处理,但是这个标记不会标记JDK自带的类,防止对JDK底层源码进行更改;也无法标记静态属性和方法
-
会创建BeanFactory注册到三级缓存中,并清空了二级缓存
-
判断是否Bean允许提前暴露,需要满足单例、支持循环依赖、以及正在被创建三个条件,这个Bean还没有填充属性,从BeanFactory获取实例,清除三级缓存,并放入二级缓存
-
填充Bean属性,执行populateBean方法
-
对Bean进行初始化操作,先判断是否实现了Aware接口,让用户感知到Bean创建,然后在执行初始化方法,最后执行Bean初始化完成的后置处理器
-
注册相关销毁逻辑
-
返回创建好的Bean
先注册在三级缓存,再从三级缓存取出实例化的原因?
源码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//bean实例包装类
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建bean的时候,这里创建bean的实例有三种方法
//1.工厂方法创建
//2.构造方法的方式注入
//3.无参构造方法注入
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//获取被包装的Bean,后续对bean的改动相当于对Wrapper的改动,反之依然
final Object bean = instanceWrapper.getWrappedInstance();
//获取实例化对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//调用BeanDefinition属性合并完成后的BeanPostProcessor后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
//被@Autowired、@Value标记的属性在这里获取
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
//向容器中缓存单例模式的Bean对象,以防循环引用
//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
//这里判断的逻辑主要有三个:
//1.是否为单例
//2.是否允许循环引用
//3.是否是在创建中的bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//Bean对象的初始化,依赖注入在此触发
//这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
Object exposedObject = bean;
//填充bean实例的属性
populateBean(beanName, mbd, instanceWrapper);
//初始化bean,过程如下:
//1:判断是否实现了BeanNameAware,BeanClassLoaderAware,
// BeanFactoryAware方法,如果有,则设置相关的属性
//2: 调用bean初始化的前置(BeanPostProcessor)操作
//3: 执行初始化的方法。
// 如果有initializingBean,则调用afterPropertiesSet
// 如果有InitMethod,则调用初始方法
//4: 调用bean初始化的后置(BeanPostProcessor)操作
exposedObject = initializeBean(beanName, exposedObject, mbd);
//若允许循环依赖,则解决相关的循环依赖
if (earlySingletonExposure) {
//获取指定名称的已注册的单例模式Bean对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//如果经过initializeBean执行后返回的bean还是同一个(不是代理对象实例,即没有被增强)
if (exposedObject == bean) {
// 确保根据名称获取到的的已注册的Bean和正在实例化的Bean是同一个
exposedObject = earlySingletonReference;
}
//如果上面的if没通过,则表明引用的bean和注入的bean不一致,则需要看看依赖于此Bean的先前是否已经注入了不完善的Bean
// allowRawInjectionDespiteWrapping 标注是否允许此Bean的原始类型被注入到其它Bean里面,
// 即使自己最终会被包装(代理)
// dependentBeanMap记录着每个依赖于此Bean的Bean实例集合
//当发生循环引用时不允许新创建实例对象
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
//获取依赖于当前Bean的Bean实例
for (String dependentBean : dependentBeans) {
//移除掉只是用来进行类型检查的单例Bean
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
/**
* 因为bean创建后其所依赖的bean一定是已经创建的
* actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有全部创建完,也就是说存在循环依赖
*/
if (!actualDependentBeans.isEmpty()) {
//....
}
}
}
}
//注册Bean的销毁逻辑
registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
3. 如何解决循环依赖
如果A依赖B,B依赖A
- 假设A先开始创建,会进行doCreateBean的处理,生成一个没有任何属性的实例
- 将A实例对应的ObjectFactory放入三级缓存,此时只有三级缓存保存了实例
- 对A进行属性赋值,此时会尝试获取实例B,由于还没有创建,就会递归进入doCreateBean创建实例B
- 将B实例对用的ObjectFactory放入三级缓存,此时三级缓存保存了A和B实例
- 对B实例进行赋值时,会调用getBean方法尝试从三级缓存中获取A实例,此时就可以获取到A的实例,并完成赋值
- 获取到A实例后,就会将该实例放入二级缓存,并清除三级缓存
- 方法返回A的属性赋值,将完整的B实例注册到A实例的属性中
- 两个实例放入一级缓存,清空其他的缓存
4. Spring都会出现哪些情况的循环依赖?
- 构造器循环依赖
- Setter注入循环依赖
构造器循环依赖
@Repository
public class Company {
private Staff staff;
@Autowired
public Company(Staff staff){
this.staff = staff;
}
}
@Repository
public class Staff {
private Company company;
@Autowired
public Staff(Company company){
this.company = company;
}
}
Setter注入循环依赖
@Repository
public class BoyFriend {
@Autowired
private GirlFriend girlFriend;
}
@Repository
public class GirlFriend {
@Autowired
private BoyFriend boyFriend;
}
-
不支持原型模式的循环依赖的:没有提供了三级缓存的机制支持,只能通过Bean名字放入缓存中阻断三级缓存
-
对于构造器单例循环依赖问题:因为创建无属性Bean的时候,构造器依赖其他Bean,无法放入第三级缓存中,就会出现循环的调用
源码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
//克隆一份BeanDefinition,用来设置上加载出来的class对象
//之所以后续用该副本操作,是因为不希望将解析的class绑定到缓存里的BeanDefinition
//因为class有可能是每次都需要动态解析出来的
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//校验和准备Bean中的方法覆盖
mbdToUse.prepareMethodOverrides();
//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
//resolveBeforeInstantiation只是针对有自定义的targetsource,
// 因为自定义的targetsource不是spring的bean那么肯定不需要进行后续的一系列的实例化,初始化。
// 所以可以在resolveBeforeInstantiation直接进行proxy
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
//创建Bean的入口
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
七、容器的Bean依赖注入
这个是doCreatBean方法里面的populateBean方法
处理逻辑
- 如果注册了后置处理器,要在设置属性前去修改Bean状态,也可以控制是否继续给Bean设置属性值,这时用户已经赋值了
- 针对XML配置,如果配置了是按名字装配或者按照类型,则先保存这个配置
- 调用后置处理器,对没有经过第二步处理的属性进行处理,比如说通过注解注入的,尝试从容器的缓存中获取,而且@Autowire并非非得按照类型来查找,在根据类型没有找到时,会尝试使用类型的名字按照名字装配或者按照别名装配
- 注解装配完成后,就会注入XML方式配置的
- 注入的Bean实例并非直接反射创建,而是还是要通过getBean方法从三级缓存获取或者创建一个新的,注入的方式还是通过反射设置
源码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 给InstantiationAwareBeanPostProcessors最后一次机会在属性注入前修改Bean的属性值,也可以控制是否继续填充Bean
// 具体通过调用postProcessAfterInstantiation方法,如果调用返回false,表示不必继续进行依赖注入,直接返回
// 主要是让用户可以自定义属性注入。比如用户实现一个 InstantiationAwareBeanPostProcessor 类型的后置处理器,
// 并通过 postProcessAfterInstantiation 方法向 bean 的成员变量注入自定义的信息。
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
//如果上面设置 continueWithPropertyPopulation = false,表明用户可能已经自己填充了
// bean 的属性,不需要 Spring 帮忙填充了。此时直接返回即可
if (!continueWithPropertyPopulation) {
return;
}
// pvs是一个MutablePropertyValues实例,里面实现了PropertyValues接口,
// 提供属性的读写操作实现,同时可以通过调用构造函数实现深拷贝
//获取BeanDefinition里面为Bean设置上的属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 根据Bean配置的依赖注入方式完成注入,默认是0,即不走以下逻辑,所有的依赖注入都需要在xml文件中有显式的配置
// 如果设置了相关的依赖装配方式,会遍历Bean中的属性,根据类型或名称来完成相应注入,无需额外配置
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据beanName进行autowiring自动装配处理
// <bean id="boyFriend" class="com.imooc.dao.impl.BoyFriend" autowire="byName"></bean>
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
//根据Bean的类型进行autowiring自动装配处理
// <bean id="boyFriend" class="com.imooc.dao.impl.BoyFriend" autowire="byType"></bean>
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 容器是否注册了InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否进行依赖检查,默认为false
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//在这里会对@Autowired标记的属性进行依赖注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 对解析完但未设置的属性再进行处理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 依赖检查,对应depend-on属性,3.0已经弃用此属性
if (needsDepCheck) {
// 过滤出所有需要进行依赖检查的属性编辑器
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
//最终将属性注入到Bean的Wrapper实例里,这里的注入主要是供
//显式配置了autowiredbyName或者ByType的属性注入,
//针对注解来讲,由于在AutowiredAnnotationBeanPostProcessor已经完成了注入,
//所以此处不执行
applyPropertyValues(beanName, mbd, bw, pvs);
}
}