目录
前言
本文分析spring循环依赖,我们知道
- 构造函数填充属性是天然无法解决循环依赖的,而且解决循环依赖必须至少需要一个单例bean提前暴露。
- 用xml标签配置属性bean,和@autowire注解注入属性bean,注入属性过程是不一样的。
(1)xml标签配置属性bean是在解析xml过程中直接将属性值填充到beanDefinition里,在populateBean填充属性时,可以从beanDefinition里读取getPropertyValues。
(2)@autowire注解注入属性bean,需要用到AutowiredAnnotationBeanPostProcessor用postProcessProperties()方法读取标有@autowire注解的属性。
本篇采用两个单例bean,通过@autowire注解属性互相依赖,作为例子,解析spring是如何实现循环依赖。
测试代码准备
实体类
/**
* @author yuxuefei
* @date 2021/1/6 10:21
*/
@Component("student")
public class Student {
@Autowired
private Teacher teacher;
private String name = "张三";
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"teacher=" + teacher.getName() +
'}';
}
}
/**
* @author yuxuefei
* @date 2021/1/6 10:22
*/
@Component("teacher")
public class Teacher {
@Autowired
private Student student;
private String name = "马老师";
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"student=" + student.getName() +
'}';
}
}
xml配置
<context:component-scan base-package="yxf.spring.circular.bean" ></context:component-scan>
运行测试类
/**
* @author yuxuefei
* @date 2020/12/25 16:52
*/
public class MyXmlConfig {
public static void main(String[] args) throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("yxf/spring/instantiate/application.xml");
Student student = (Student) ac.getBean("student");
System.out.println(student);
}
}
我们准备了Student和Teacher两个实体类,并且互相都用@autowire注入彼此,属性依赖,xml中配置开启注解。下面我们开始分析啦!
执行流程分析
执行流程很长,也比较绕,只看文字很容易绕晕,所以我做了一副流程图,附在文章最后,可以对照流程图来看。
因为都是非懒加载单例bean,所以会在容器初始化阶段提前初始化所有非懒加载bean,我们的分析就从DefaultListableBeanFactory.PreInstantiateSingletons()方法开始。
DefaultListableBeanFactory.PreInstantiateSingletons()解析
代码精简后如下
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有非懒加载bean,并实例化
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象、单例、非懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//实现FactoryBean接口的实例化处理方式
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
//正常bean的实例化方式
else {
getBean(beanName);
}
}
}
}
这个方法就是提前把所有非懒加载的单例bean提前实例化,分成两种方式,一种是实现FactoryBean接口的,我们已经在《Spring源码分析系列——bean创建过程分析(四)——实现FactoryBean接口创建bean》这篇文章中解析过了。另一种就是正常的getBean方式。主要流程我们也在之前的spring解析系列文章解析过了,现在我们再解析一些跟单例bean创建的一些细节。
进入getBean(beanName)、doGetBean()方法,我们重点解析doGetBean()方法。此时第一次getBean(beanName)的beanName是"student"。
第一个实体类student的getBean()
直接进入doGetBean()方法,我们重点解析这个方法。
doGetBean()方法分析
精简了很多无关代码,如下
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 首先进一次getSingleton()方法,从单例缓存中取,第一次肯定为null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 创建单例bean
if (mbd.isSingleton()) {
//传入一个ObjectFactory的lambda表达式,这个lambda表达式调用createBean方法真正创建bean实例
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return (T) bean;
}
代码精简之后,就是调用了两次getSingleton()方法,第一次从单例缓存中取,如果没有,就第二次调用getSingleton(),传入一个ObjectFactory的lambda表达式,调用createBean真正创建bean。我们重点看一下getSingleton(beanName)方法。
DefaultSingletonBeanRegistry.getSingleton(beanName)方法分析
看一下完整代码
public Object getSingleton(String beanName) {
return getSingleton(beanName, allowEarlyReference:true);
}
调的是重载方法,且allowEarlyReference为true,即允许提前引用,之后还会遇到别的地方调用这个方法,只不过传的是false
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从一级缓存里取
Object singletonObject = this.singletonObjects.get(beanName);
//如果一级缓存里没有,并且该实例正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存里取
singletonObject = this.earlySingletonObjects.get(beanName);
//如果二级缓存里没有,并且允许使用使用三级缓存
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//如果有三级缓存
if (singletonFactory != null) {
//执行三级缓存的lambda表达式,创建实例
singletonObject = singletonFactory.getObject();
//将创建好的实例放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//移除三级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
这里就是分别从三级缓存里依次取单例。
DefaultSingletonBeanRegistry.getSingleton(beanName,ObjectFactory)重载方法分析
第一次调用getSingleton(beanName)方法肯定是没有缓存的,所以会继续调用第二个getSingleton(beanName,ObjectFactory)真正创建单例。跟第一个getSingleton不一样的是,第二个getSingleton这个重载方法传入了ObjectFactory这个lambda表达式,这个lambda表达式调用createBean()真正创建单例bean。下面我们来分析getSingleton(beanName,ObjectFactory)这个重载方法。
代码精简之后,如下
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
//依然先从一级缓存里取
Object singletonObject = this.singletonObjects.get(beanName);
//如果一级缓存没有
if (singletonObject == null) {
//标记这个单例bean正在创建
beforeSingletonCreation(beanName);
//是否新创建的单例bean标记
boolean newSingleton = false;
try {
//执行lambda表达式,创建bean
singletonObject = singletonFactory.getObject();
//新创建单例bean标记为true
newSingleton = true;
}
catch (BeanCreationException ex) {
}
finally {
//移除正在创建的单例bean标记
afterSingletonCreation(beanName);
}
//新创建的单例bean标记为true
if (newSingleton) {
//将新创建的单例bean放入一级缓存,并且将二级、三级缓存移除
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
看一下里面调用的几个简单的方法
//标记这个单例bean正在创建
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
//移除正在创建的单例bean标记
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
//将新创建的单例bean放入一级缓存,并且将二级、三级缓存移除
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
//singletonsCurrentlyInCreation 是一个set,放的是正在创建的单例bean集合,创建完成后就移除
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
创建student单例bean前后的主流程就比较清晰了,现在来看执行createBean创建student是怎么和创建teacher产生属性依赖,并解决的。
createBean()方法分析
代码精简后,如下
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// bean的包装类
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
//创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//真正创建的bean实例
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
//如果是单例、允许循环依赖并且是正在创建中的单例,添加三级缓存singletonFactory
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
//填充属性
populateBean(beanName, mbd, instanceWrapper);
//初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
//如果是单例、允许循环依赖并且是正在创建中的单例,初始化完还要检验
if (earlySingletonExposure) {
//再次调用getSingleton,注意这次传的allowEarlyReference为false,即不从三级缓存里创建bean。
Object earlySingletonReference = getSingleton(beanName, false);
//如果有提早暴漏的bean,其实是二级缓存中拿的,而二级缓存中存的其实就是由三级缓存创建的
if (earlySingletonReference != null) {
//如果初始化之后的bean和原始bean一样,就采用提早暴漏的bean
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
}
}
return exposedObject;
}
createBean()方法调用createBeanInstance()方法创建bean后,如果是单例、允许循环依赖并且是正在创建中的单例,就添加三级缓存singletonFactory,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))。lambda表达式中调用getEarlyBeanReference()方法,参数中传入了刚创建好的bean。来看一下这个方法
getEarlyBeanReference(beanName, mbd, bean))
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
如果忽略掉中间调用的beanPostProcessor,那就是将创建的原生bean再暴漏出去。
接下来就该分析填充属性了,是在populateBean()方法中填充属性,这里就该填充teacher属性了,前面提到过,由xml和@annotation两种方式设置bean定义再populateBean()填充属性时,执行过程时不一样的。我们这里是用的@annotation方式注入属性。
populateBean()方法分析
代码精简后,如下
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//从bean定义中取xml中定义的property属性。这里因为是注解注入属性,用不到
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//是否有InstantiationAwareBeanPostProcessors标记,这里因为用了注解,肯定有
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//遍历所有的BeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果是InstantiationAwareBeanPostProcessor
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//执行postProcessProperties()方法
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;
}
}
}
//xml方式注入属性,这里用不到
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
循环BeanPostProcessor里,真正起作用的是AutowiredAnnotationBeanPostProecessor。至于这些BeanPostProcessor是什么时候加载进来的,因为我们再xml中配置了
<context:component-scan base-package="edu.dongnao.courseware.spring.circular.bean" ></context:component-scan>
配置了component-scan标签,就会在ContextNamespaceHandler调用init()、parse()方法时提前实例化这些注解相关的BeanPostProcessor,其中就有AutowiredAnnotationBeanPostProcessor,详情请看这篇《Spring源码分析系列——xml配置非默认元素<context:annotation-config/> 和<context:component-scan/>是如何让注解生效的?》。
再来分析AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,至于postProcessPropertyValues()方法,其实已经废弃
源码如下
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//找到标有@autowired注解元信息
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//注入操作
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
@Deprecated
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
return postProcessProperties(pvs, bean, beanName);
}
继续看InjectionMetadata的inject()方法
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
}
element就是标有@autowired的属性
继续看InjectedElement的inject()方法(实际上是AutowiredFieldElement)
代码精简之后,如下
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//需要注入的属性,标有@autowired属性
Field field = (Field) this.member;
Object value;
//缓存中取,第一次肯定没有
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
//调用beanFactory的resolveDependency()方法,获得属性依赖的bean
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
if (value != null) {
ReflectionUtils.makeAccessible(field);
//反射注入属性
field.set(bean, value);
}
}
再看beanFactory的resolveDependency()方式是如何获取属性bean的
代码精简之后,如下
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
就是委托给doResolveDependency()方法
代码精简后,如下
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
try {
Class<?> type = descriptor.getDependencyType();
//找到候选的@autowired注解属性,Object有可能是Class也有可能bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
String autowiredBeanName;
Object instanceCandidate;
//多个候选bean时处理方案
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
//只有一个候选时
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
//如果是Class则解析成bean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
return result;
}
}
再来看DependencyDescriptor.resolveCandidate()方法
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
很明显,调用的是getBean(beanName)方法获取需要注入的属性bean:“teacher”。
下面开始第二个bean,"teacher"的getBean()
第二个实体类teacher的getBean()
已经来到了第二个实体类teacher的getBean(),继续doGetBean()。在第一个实体类student的getBean()中已经对doGetBean()解析过了,是会执行两次getSingleton()方法(两次是不一样的重载方法),我们再来简单看一下
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
doCreateBean()创建实例并填充属性
不再分析了,接着跟创建student时流程一样,都是执行createBeanInstance()创建bean实例,然后进入populateBean()填充属性阶段。这时候student和teacher都处于populateBean()填充属性阶段,一级缓存和二级缓存中都没有student和teacher的缓存,而在三级缓存中已经包含了student和teacher的缓存创建工厂,因为两者都执行完了createBeanInstance()创建实例方法,在createBeanInstance()和populateBean()方法之间会把三级缓存用的缓存创建工厂加入到三级缓存,调用的是addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))方法。
所以在teacher填充student属性时,调用getBean(“student”)方法,再调用doGetBean(),再第一次调用getSingleton()方法,因为allowEarlyReference=true,所以会调用三级缓存,执行ObjectFactory的lambda表达式,获取回调创建的bean。执行完后再把三级缓存移除,放入二级缓存。
由此,可以看出来了,在创建第一个实体类student的时候提前暴露到三级缓存,然后在第二个实体类创建后进入填充属性过程getBean()时,直接从三级缓存中拿到第一个实体类的bean,从而解决死循环问题。
第二个实体类创建完毕,放入单例池,继续回到第一个实体类填充属性方法
第二个实体类teacher填充完属性后,自身继续执行剩下的创建过程,放入一级缓存中,并移除二级、三级缓存。因为第二个实体类teacher的创建是由第一个实体类student在populateBean()填充属性阶段getBean(“teacher”)触发的,所以getBean(“teacher”)执行完后,继续回到student的populateBean()阶段。这个时候student属性赋值为刚创建的teacher。
之后同样将创建完的student放入一级缓存,且移除二级缓存和三级缓存,循环引用完美解决。
疑问
为什么需要三级缓存?只用一级、二级不行吗?
只用一级显然是不行的,因为提前暴漏的bean还没有进行属性赋值和初始化,并不完整,不能给外界用,所以需要一个二级缓存,专门存储只进行了实例化,尚未进行属性赋值和初始化的不完整bean。我们看一下添加三级缓存的代码addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
就是对刚创建的bean做了一些预留扩展处理,如果没有这些处理,就是直接返回回调的bean,正常的bean是没问题的。但是如果需要提前暴露的bean(student)会被aop代理,最终提供的单例bean就是被aop代理后的bean,那么在给teacher引用前就必须得先创建好代理后的student,否则teacher引用的就是代理前的student了。这时候三级缓存中的singletonFactory就可以执行创建aop代理的对象了。这里的SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference(exposedObject, beanName)实际上就是做的aop代理增强。
三级缓存的真正用途及提前暴露aop代理对象真正返回的bean
具体创建aop的逻辑来看一下
SmartInstantiationAwareBeanPostProcessor的实现类默认只有一个AbstractAutoProxyCreator,这个类正是创建Aop代理的。
看一下getEarlyBeanReference的方法实现
// AbstractAutoProxyCreator.java
public Object getEarlyBeanReference(Object bean, String beanName) {
// 缓存当前bean,表示该bean被提前代理了
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 对bean进行提前Spring AOP代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
wrapIfNecessary是用于Spring AOP自动代理的。Spring将当前bean缓存到earlyProxyReferences中标识提前曝光的bean在被提前引用之前,然后进行了Spring AOP代理。但是经过Spring AOP代理后的bean就已经不再是原来的bean了,经过代理后的bean是一个全新的bean,也就是说代理前后的2个bean连内存地址都不一样了。这时将再引出新的问题:B提前引用A将引用到A的代理,这是符合常理的,但是最原始的bean A在B完成创建后将继续创建,那么Spring Ioc最后返回的Bean是Bean A呢还是经过代理后的Bean呢?
这个问题我们得回到Spring AOP代理,Spring AOP代理时机有2个:
当自定义了TargetSource,则在bean实例化前完成Spring AOP代理并且直接发生短路操作,返回bean
正常情况下,都是在bean初始化后进行Spring AOP代理
如果要加上今天说的提前曝光代理,getEarlyBeanReference可以说3种
第一种情况就没什么好探究的了,直接短路了,根本没有后续操作。而我们关心的是第二种情况,在Spring初始化后置处理器中发生的Spring AOP代理
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 调用bean初始化后置处理器处理
Object current = processor.postProcessAfterInitialization(result,
beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
// AbstractAutoProxyCreator.java
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
// 获取缓存key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 查看该bean是否被Spring AOP提前代理!而缓存的是原始的bean,因此如果
// bean被提前代理过,这此处会跳过
// 如果bean没有被提前代理过,则进入AOP代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
earlyProxyReferences是不是有点熟悉,是的,这就是我们刚刚提前曝光并且进行Spring AOP提前代理时缓存的原始bean,如果缓存的原始bean跟当前的bean是一至的,那么就不进行Spring AOP代理了!返回原始的bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
try {
//
/**
* 4. 填充属性
* 如果@Autowired注解属性,则在上方完成解析后,在这里完成注入
*
* @Autowired
* private Inner inner;
*/
populateBean(beanName, mbd, instanceWrapper);
// 5. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 6. 存在提前曝光情况下
if (earlySingletonExposure) {
// earlySingletonReference:二级缓存,缓存的是经过提前曝光提前Spring AOP代理的bean
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// exposedObject跟bean一样,说明初始化操作没用应用Initialization后置处理器(指AOP操作)改变exposedObject
// 主要是因为exposedObject如果提前代理过,就会跳过Spring AOP代理,所以exposedObject没被改变,也就等于bean了
if (exposedObject == bean) {
// 将二级缓存中的提前AOP代理的bean赋值给exposedObject,并返回
exposedObject = earlySingletonReference;
}
// 引用都不相等了,也就是现在的bean已经不是当时提前曝光的bean了
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// dependentBeans也就是B, C, D
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 被依赖检测异常
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
}
这个时候我们需要理清一下3个变量
earlySingletonReference: 二级缓存,缓存的是经过提前曝光提前AOP代理的bean
bean: 这个就是经过了实例化、填充、初始化的bean
exposedObject: 这个是经过了AbstractAutoProxyCreator的postProcessAfterInitialization处理过后的bean,但是在其中因为发现当前bean已经被earlyProxyReferences缓存,所以并没有进行AOP处理,而是直接跳过,因此还是跟第2点一样的bean
理清这3个变量以后,就会发现,exposedObject = earlySingletonReference;
AOP代理过的Bean赋值给了exposedObject并返回,这时候用户拿到的bean就是AOP代理过后的bean了,一切皆大欢喜了。
但是中间还有一个问题!提前曝光的bean在提前引用时被Spring AOP代理了,但是此时的bean只是经过了实例化的bean,还没有进行@Autowire的注入啊!也就是说此时代理的bean里面自动注入的属性是空的!
是的,确实在Spring AOP提前代理后没有经过属性填充和初始化。那么这个代理又是如何保证依赖属性的注入的呢?答案回到Spring AOP最早最早讲的JDK动态代理上找,JDK动态代理时,会将目标对象target保存在最后生成的代理 p r o x y 中,当调用 proxy中,当调用 proxy中,当调用proxy方法时会回调h.invoke,而h.invoke又会回调目标对象target的原始方法。
因此,其实在Spring AOP动态代理时,原始bean已经被保存在提前曝光代理中了。而后原始Bean继续完成属性填充和初始化操作。因为AOP代理$proxy中保存着traget也就是是原始bean的引用,因此后续原始bean的完善,也就相当于Spring AOP中的target的完善,这样就保证了Spring AOP的属性填充与初始化了!
去掉原有的二级缓存earlySingletonObjects,直接用三级缓存singletonFactories可以吗?
Spring是通过一级缓存(singletonObjects)、二级缓存(earlySingletonObjects)、三级缓存(singletonFactories)构成了三层缓存的模式。
如果去掉二级缓存(earlySingletonObjects),只使用一级缓存(singletonObjects)和三级缓(singletonFactories)的话,对于普通的bean没有影响,但对于AOP代理的bean会导致重复创建bean实例,违法了单例原则。
比如有三个类Bean1、Bean2、Bean3,3个类各自持有其他两个类的属性,其中Bean1需要Aop代理,Bean2、Bean3是正常类。假如先从Bean1开始创建,属性注入Bean2的时候开始创建Bean2,Bean2属性注入Bean1的时候执行三级缓存创建Bean1的Aop代理并引用,接着Bean2属性注入Bean3的时候开始创建Bean3,Bean3属性注入Bean1的时候本来可以直接从原来的二级缓存earlySingletonObjects中取(三级缓存的Bean1创建后会放到二级缓存并从三级缓存中移除自己),现在没有了,再次从执行了三级缓存的getObject,又创建了一遍Bean1的Aop代理类,违反了单例原则。
总结
spring循环依赖解决方案
使用三级缓存解决单例bean的循环依赖,在第一个实体类createBeanInstance()方法创建完bean实例,和populateBean()填充属性之间,添加三级缓存实例创建工厂,实现提前暴漏,这样在第二个实体类填充第一个实体类属性时,通过getSingleton()方法获取三级缓存中提前暴漏的第一个实体类创建的bean,从而解决循环依赖。
在没有循环依赖的情况下,二级缓存没有使用到,三级缓存只是添加了该bean的singletonFactory并没有执行,只有真正遇到循环依赖的时候才会用到二、三级缓存
循环依赖时三级缓存缺一不可,一些场景下各有用途
一级缓存singletonObjects:完整的单例bean
二级缓存earlySingletonObjects:多个bean互相循环依赖时,提前暴露的bean需要被Aop代理,则提前创建好的代理类需要放到二级缓存,防止多次创建代理,违反单例原则
三级缓存singletonFactories:提前暴露的bean需要被Aop代理,则被循环依赖时需要提前创建代理
解决循环依赖核心执行流程
我们使用beanA指代第一个实体类,beanB指代第二个实体类。
1.beanA开始创建=== 》
2. getBean() === 》
3. doGetBean() === 》
4. 第一次getSingleton(),无缓存单例 === 》
5. 第二次getSingleton(),执行ObjectFactory 的createBean()创建bean实例 === 》
6. doCreateBean() === 》
7. createBeanInstance()创建bean实例 === 》
8. 三级缓存中添加beanA的缓存创建工厂,提前暴漏beanA === 》
9. populateBean()填充属性,执行过程中,调用getBean(),开始创建beanB === 》
10. getBean() === 》
11. doGetBean() === 》
12. 第一次getSingleton(),无缓存单例 === 》
13. 第二次getSingleton(),执行ObjectFactory 的createBean()创建bean实例 === 》
14. doCreateBean() === 》
15. createBeanInstance()创建bean实例 === 》
16. 三级缓存中添加beanB的缓存创建工厂,提前暴漏beanB,(对于只有beanA和beanB循环依赖,beanB的缓存创建工厂没有用到,如果是beanA、beanB、beanC三者循环依赖,就会用到了) === 》
17. populateBean()填充属性,执行过程中,调用getBean(),尝试获取beanA === 》
18. getBean() === 》
19. doGetBean() === 》
20. 第一次getSingleton(),从三级缓存中调用缓存创建工厂,回调一开始创建的beanA(beanA此时还在执行populateBean填充beanB中)=== 》
21. 拿到beanA,直接返回,完成populateBean() === 》
22. initializeBean()初始化 === 》
23. 完成beanB的创建、属性填充、初始化,并放入一级缓存,移除二级、三级缓存 === 》
24. beanA的populateBean填充属性beanB完成 === 》
25. initializeBean() 初始化 === 》
26. 完成beanA的创建、属性填充、初始化,并放入一级缓存,移除二级
、三级缓存 。至此,beanA和beanB都创建完毕,并放入一级缓存中。
以上完整流程,从头到尾都是在beanA的创建过程中,从9-23都是在执行populateBean()方法对beanA属性填充beanB,所以会开始beanB的创建。
在第8步中,关键的在三级缓存中添加beanA的缓存创建工厂,提前暴漏beanA,所以在20步beanB填充属性beanA时,调用getSingleton才能拿到三级缓存中的beanA。