Spring Bean 生命周期探究 以及 如何解决循环依赖

概述

这篇文章是看了子路老师视频后总结的笔记,子路老师在 Spring 源码方面造诣颇深,这里有两个他的视频推荐诸位:
spring源码-bean的生命周期
spring源码-spring循环依赖

1. Spring bean 和对象?

  • spring bean——受 spring 容器管理的对象,可能经过了完整的 spring bean 生命周期,最终存在spring容器当中,bean 是由 Spring IoC 容器实例化、组装和管理的对象;一个bean一定是个对象
  • 对象——任何符合java语法规则实例化出来的对象,但是一个对象并不一定是spring bean

2. 项目结构搭建

下面用 IDEA 新建一个 maven 工程,导入 Spring 相关 jar 包,用一个 Demo 演示 Spring bean 生命周期过程:注意这里使用注解的方式创建对象

@Component
public class Teacher {
    
    
    public Teacher() {
    
    
        System.out.println("Teacher constructor....");
    }
}
@Component
public class User {
    
    
    public User() {
    
    
        System.out.println("User constructor....");
    }
}
@ComponentScan("com.lhg.demo.*")
public class App{
    
    
    public static void main( String[] args ){
    
    
        ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
        ac.getBean("user")
   }
}
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.5.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.5</version>
  </dependency>
</dependencies>

3. Spring 创建 bean 的过程源码分析

 ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
 ac.getBean("user")

进入 AnnotationConfigApplicationContext 类的构造方法

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
    
    
    public AnnotationConfigApplicationContext() {
    
    
        //由于这个类继承自GenericApplicationContext,
        //按照 java 语法,无参构造方法的首行默认调用父类的无参构造方法
        //初始化一个读取器和扫描器
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    } 
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    
    
        this();//this 表示调用当前类的无参构造方法
        this.register(annotatedClasses);
        this.refresh();
    }
}

如果是用 xml 配置的方式

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) ac.getBean("user");

查看源码,会发现同样要调用 refresh 方法

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    
    
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    
    
		this(new String[] {
    
    configLocation}, true, null);
	}
	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
    
    
	    super(parent);
	    this.setConfigLocations(configLocations);
	    if (refresh) {
    
    
	        this.refresh();
	    }
	}
}
3.1 this 调用父类构造方法

this 表示调用当前类(AnnotationConfigApplicationContext)的无参构造方法,如果类有继承关系,按照 java 语法,无参构造方法的首行默认调用父类的无参构造方法,即调用 GenericApplicationContext 父类构造方法

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    
    
    //beanFactory 就是 bean 工厂,而在 DefaultListableBeanFactory 类中有个叫 beanDefinitionMap 的 map 容器
    private final DefaultListableBeanFactory beanFactory;
    public GenericApplicationContext() {
    
    
        this.customClassLoader = false;
        this.refreshed = new AtomicBoolean();
        //可以看到在这里初始化了 beanFactory
        this.beanFactory = new DefaultListableBeanFactory();
    }
}
3.2 this.register(annotatedClasses) 方法

如果我们用了 Spring 注解,比如 Component 注解,Spring会自己扫描,这个方法的目的其实就一句this.beanDefinitionMap.put(beanName, beanDefinition),点进源码,发现最终调用如下方法

public class AnnotatedBeanDefinitionReader {
    
    
	<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    
    
        	//.....这里省略的代码就是把一个类变成 BeanDefinite 的过程
         
        	//BeanDefinitionHolder 其实就包含了 BeanDefinite,到此为止,JavaConfig 就变成了一个BeanDefinition
            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }
}

从debug 图可以看到,此时 App 类还未变成 BeanDefinition对象(后面我以 bd 略称),没有放入beanDefinateMap 中
在这里插入图片描述

为什么要把 类封装成 bd 而不是直接 class 对象呢?

因为 bd 可以包含更丰富的类信息,比如是否抽象类,是否单例/原型,是否懒加载…

ok,继续往下进入 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); 方法,DefaultListableBeanFactory 类中可以看到 beanDefinitionMap 的定义

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    
	/** Map of bean definition objects, keyed by bean name. */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

  	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
    
    
		//省略代码。。。
		//beanName 就是 App,显然 existingDefinition 为 null
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
    
    
		    ...
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
    
    
			if (hasBeanCreationStarted()) {
    
    
				....
			}
			else {
    
    
				// Still in startup registration phase
				//在这里把封装后的 beanDefinition 放入 map 中了
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		...
	}
}

经过 debug 也证实了我们的推断
在这里插入图片描述

3.3 this.refresh()方法分析

到目前为止,我们发现 User 对象和 Teacher 对象还没有被扫描,放入beanDefinitionMap 中,

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
    
    
	public void refresh() throws BeansException, IllegalStateException {
    
    
        synchronized(this.startupShutdownMonitor) {
    
    
            //准备工作包括设置启动时间,是否激活标志位
            //初始化属性源(propertry source)配置
            this.prepareRefresh();
            //返回一个 facotory 工厂,为什么需要返回一个工厂?
            //因为要对工厂进行初始化
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备工厂
            this.prepareBeanFactory(beanFactory);

            try {
    
    
                //这个方法里是没有任何代码的,可能是为了以后的 Spring 扩展吧...
                this.postProcessBeanFactory(beanFactory);
                //在 Spring 环境中去执行已经被注册的 factory processors,
                //设置执行自定义的 ProcessBeanFactory 和 Spring 内部定义的的
                //在进入 refresh 方法之前,已经进行了 scan----- put map----invokeBeanFactoryPostProcessors{1.custom 2.内置的}
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                //实例化对象
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
    
    
                ....
                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            }...
        }
    }
}

经过断点调试,发现执行完 this.invokeBeanFactoryPostProcessors(beanFactory); 方法后 user 和 teacher 类 变成 bd 并放入 beanDefinateMap 中了

在这里插入图片描述
上段代码注释我说了,this.invokeBeanFactoryPostProcessors(beanFactory);在执行的时候会看看用户是否有自定义实现 BeanFactoryPostProcessors ,如果有,也会执行用户自定义的 BeanFactoryPostProcessors,可以实现对 spring的扩展

@Component
public class CustomerBeanFactoryProcessor implements BeanFactoryPostProcessor {
    
    
    /**
     * 你可以看到形参是 DefaultListableBeanFactory 的父类 configurableListableBeanFactory
     * 这是因为如果要兼容 ClassPathXmlApplicationContext("application.xml")的初始化情况
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    
    

        /**
         * 我们用 BeanDefinition 的子类,因为子类实现了更丰富的方法
         * BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("student");
         * **/
        //这里我们通过 BeanFactory 先拿到的是 beanDefinite
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("user");
        //获取到 beanDefinite 后,便可以通过beanDefinite得到 bean 了
        System.out.println("原来的bean:"+beanDefinition.getBeanClassName());
        //当然你可以偷梁换柱,替换成其它的类
        beanDefinition.setBeanClass(Teacher.class);
        System.out.println("后来的bean:"+beanDefinition.getBeanClassName());
    }
}
ApplicationContext ac = new AnnotationConfigApplicationContext(App.class);
//本意是输出 user 对象
System.out.println(ac.getBean("user"));

运行后的结果:最后得到是 Teacher 对象

D:\ProgramFiles\Java\jdk1.8.0_201\bin\java.exe "-javaagent:
原来的bean:com.lhg.demo.config.User
后来的bean:com.lhg.demo.config.Teacher
Teacher constructor....
Teacher constructor....
com.lhg.demo.config.Teacher@2a70a3d8

Process finished with exit code 0

那到底什么叫 BeanFactoryPostProcessor 呢?

所谓的 BeanFactoryPostProcessor,就是能够干扰 Spring Bean 初始化的过程,像上面我们自定义的 CustomerBeanFactoryProcessor 类就可以看出,我们明明要的是 user 对象,经过自定义的BeanFactoryPostProcessor 内部处理,输出却变成了另外的 Teacher 对象…

finishBeanFactoryInitialization(beanFactory);

执行完 invokeBeanFactoryPostProcessors() 方法后,user 和 teacher 虽然已经变成了 bd 并放入了 beanDefinateMap 中,但是查看控制台发现它们的构造方法还是没有被执行,当执行完 finishBeanFactoryInitialization(beanFactory); 方法后才执行了构造方法,也就是在 finishBeanFactoryInitialization 方法最终实例化了对象,所以我们需要查看 finishBeanFactoryInitialization(beanFactory); 方法实现。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    
	@Override
	public void preInstantiateSingletons() throws BeansException {
    
    
		//...
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		//遍历 map
		for (String beanName : beanNames) {
    
    
			//通过 beanName 获得 bd 对象
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//各种验证
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    
    
				if (isFactoryBean(beanName)) {
    
    //为 false,不是个 factorybean
					//....
				}
				else {
    
    
					getBean(beanName);
				}
			}
		}
	}
}

接着查看 getBean(beanName); 底层方法实现,注意到下面方法 getSingleton 是两个重载的方法,通过 debug 调试发现,在第二次调用 getSingleton 方法后 bean 被创建出来了,换言之整个 bean 如何被初始化的都是在这个方法里面;至此本文当中例举出来的 doGetBean 方法的核心代码看起来解析完成了;

如下是精简了的 doGetBean 方法;

再次强调,第一次调用 getSingleton 方法也很重要,里面有解决循环依赖的逻辑

接下来就要研究第二次 getSingleton方法的内容了,因为我说了整个bean初始化过程都在里面体现了

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
    

	final String beanName = transformedBeanName(name);
	Object bean;
	// Eagerly check singleton cache for manually registered singletons.
	//第一次调用getSingleton: 因为是第一次初始化,这里 sharedInstance 显然是为 null,
	//里面的逻辑是实现循环依赖最主要的代码,后文详说
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
    
    
		....
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
    
    
		...
		try {
    
    
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			...
			// Create bean instance.
			if (mbd.isSingleton()) {
    
    
				//第二次调用getSingleton,完成了bean的初始化
				sharedInstance = getSingleton(beanName, () -> {
    
    
					try {
    
    
						return createBean(beanName, mbd, args);
					}
					...
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			else if (mbd.isPrototype()) {
    
    
				// It's a prototype -> create a new instance.
				...
			}
		}
		...
	}
	...
	return (T) bean;
}

第二次调用 getSingleton 使用了 lambda 表达式,首先就是执行 getSingleton(beanName, singletonFactory) 方法了,这个就有意思了,重点

	/**
	 * Return the (raw) singleton object registered under the given name,
	 * creating and registering a new one if none registered yet.
	 * @param beanName the name of the bean
	 * @param singletonFactory the ObjectFactory to lazily create the singleton
	 * with, if necessary
	 * @return the registered singleton object
	 */
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
    
    
			Object singletonObject = this.singletonObjects.get(beanName);
			//在spring 初始化bean的时候这里肯定为空,故而成立
			if (singletonObject == null) {
    
    
				if (this.singletonsCurrentlyInDestruction) {
    
    
					throw new BeanCreationNotAllowedException(beanName,
							"...");
				}
				...
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
    
    
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
    
    
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				...
				if (newSingleton) {
    
    
					//这个方法里面 把 bean 放入了单例池,singletonObjects,完成了生命周期
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

第二次 getSingleton 上来便调用了 this.singletonObjects.get(beanName),直接从单例池当中获取这个对象,由于这里是创建故而一定返回null;singletonObjects 是一个map集合,即所谓的单例池;用大白话说 spring 所有的单例 bean 实例化好都存放在这个map当中,很多读者包括我以前认为这就是 所谓的 spring 容器,但其实这种理解是错误的,因为 spring 容器的概念比较抽象,而单例池只是 spring 容器的一个组件而已;我们经常说的 Spring 容器其实是指的是 beanDefinitionMap、BeanFactoryPostProcessors、singletonObjects等组合起来的

可以看看 singletonObjects 的定义

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

这行代码其实比较简单,判断当前实例化的bean是否正在销毁的集合里面;spring不管销毁还是创建一个bean 的过程都比较繁琐,都会先把他们放到一个集合当中标识正在创建或者销毁;

if (this.singletonsCurrentlyInDestruction) {
    
    
	throw new BeanCreationNotAllowedException(beanName, "...");
}

下面这段代码就比较重要了,关于上面说那个正在创建和正在销毁的集合,我们来看看 beforeSingletonCreation 这个方法,很重要

  • this.inCreationCheckExclusions.contains(beanName)这里是判断当前需要创建的bean是否在Exclusions集合,被排除的bean,程序员可以提供一些bean不被spring初始化(哪怕被扫描到了,也不初始化),那么这些提供的bean便会存在这个集合当中;一般情况下我们不会提供,而且与循环依赖无关;故而所以这里不做深入分析,后面文章如果写到做分析;

  • this.singletonsCurrentlyInCreation.add(beanName),如果当前bean不在排除的集合当中那么则这个bean添加到singletonsCurrentlyInCreation(当然这里只是把bean名字添加到集合,,因为他能根据名字能找打对应的bean)

/**
 * Callback before singleton creation.
 * <p>The default implementation register the singleton as currently in creation.
 * @param beanName the name of the singleton about to be created
 * @see #isSingletonCurrentlyInCreation
 */
protected void beforeSingletonCreation(String beanName) {
    
    
	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
    
    
		throw new BeanCurrentlyInCreationException(beanName);
	}
}
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

当代码执行到这儿的语境,综合以上代码可以看出,当 spring 觉得可以着手来创建 bean 的时候首先便是调用 beforeSingletonCreation(beanName);判断当前正在实例化的 bean 是否存在正在创建的集合当中,说白了就是判断当前是否正在被创建;因为 spring不管创建原型 bean 还是单例 bean,当他需要正式创建 bean 的时候他会记录一下这个bean正在创建(add到一个set集合当中);故而当他正式创建之前他要去看看这个bean有没有正在被创建(是否存在集合当中);
在这里插入图片描述

为什么 spring 要去判断是否存在这个集合呢?

原因很多除了你们能想到了(你们能想到的基本不会出现,比如并发啊,重复创建什么的,因为他已经做了严格并发处理),其实这个集合主要是为了循环依赖服务的,后文再说怎么解决循环依赖

注意: 代码执行完 this.singletonsCurrentlyInCreation.add(beanName) 之后可以看到singletonsCurrentlyInCreation 集合当中已经有 对象了,但是 控制台并没有打印构造方法,说明spring 仅仅是把 user 添加到正在创建的集合当中,但是并没有完成 bean 的创建;在这里插入图片描述

接下来就是执行 createBean,获得 class、推断构造方法、并反射,实例化对象,把创建好的 bean 返回出来

/**
	 * Central method of this class: creates a bean instance,
	 * populates the bean instance, applies post-proce ssors, etc.
	 * @see #doCreateBean
	 */
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
    
    
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	//得到 class
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
    
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
    
    
		mbdToUse.prepareMethodOverrides();
	}
	try {
    
    
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
    
    
			return bean;
		}
	}
	...
	try {
    
    
		//在 doCreateBean 方法中创建对象
		//推断构造方法,并反射,实例化对象
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
    
    
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {
    
    

	// Instantiate the bean.
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
    
    
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
    
    
		//在这个方法里面完成了对象的创建
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	final Object bean = instanceWrapper.getWrappedInstance();
	Class<?> beanType = instanceWrapper.getWrappedClass();
	// Allow post-processors to modify the merged bean definition.
	//从 java-doc 可以看出这里说的是可以通过 post-processors 去 modify 合并的 beandefinition.
	synchronized (mbd.postProcessingLock) {
    
    
		if (!mbd.postProcessed) {
    
    
			try {
    
    
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			}
			catch (Throwable ex) {
    
    
				...
			}
			mbd.postProcessed = true;
		}
	}
	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//从 java-doc 可以看出这里是 缓存对象来解决循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		...
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
    
    
		//完成属性填充
		//比如 A类里面有个 B,那么这个方法就是完成 B 的注入
		populateBean(beanName, mbd, instanceWrapper);
		//主要执行各种生命周期回调方法以及 AOP 等
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	...
}
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    
	// Make sure bean class is actually resolved at this point.
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    
    
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}

	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
    
    
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	if (mbd.getFactoryMethodName() != null) {
    
    
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// Shortcut when re-creating the same bean...
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
    
    
		synchronized (mbd.constructorArgumentLock) {
    
    
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
    
    
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	if (resolved) {
    
    
		if (autowireNecessary) {
    
    
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
    
    
			return instantiateBean(beanName, mbd);
		}
	}

	// Candidate constructors for autowiring?
	// 如果是自动装配,推断出各种候选的构造方法
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    
    
		//通过推断出的构造方法反射创建对象	
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// Preferred constructors for default construction?
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
    
    
		return autowireConstructor(beanName, mbd, ctors, null);
	}

	// No special handling: simply use no-arg constructor.
	//如果没有推断出合适构造方法,则使用默认的构造方法
	return instantiateBean(beanName, mbd);
}

注意: createBeanInstance 顾名思义就是创建一个实例,此时构造方法已经获得执行,但是这里仅仅是创建一个实例对象,还不能称为 bean,只有当 对象 put 进单例池才能算走完整个生命周期
在这里插入图片描述
继续来看 createBeanInstance 方法

	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	//从 java-doc 可以看出这里是 缓存对象来解决循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		...
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

earlySingletonExposure这个布尔变量的赋值逻辑是怎样的呢?上面代码可知三个条件做&&运算,同时成立才会返回true;
1、mbd.isSingleton();判断当前实例化的bean是否为单例;再一次说明原型是不支持循环依赖的;因为如果是原型这里就会返回false,由于是&&运算,整个结果都为false;
2、this.allowCircularReferences;整个全局变量 spring 默认为 true;当然spring提供了api 供程序员修改,在没有修改的情况下这里也返回true

 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
 ac.setAllowCircularReferences(false); // 设置 false ,不支持循环引用
 ac.register(App.class);
 ac.refresh();
 System.out.println(ac.getBean("user"));

3、isSingletonCurrentlyInCreation(beanName);判断当前正在创建的 bean 是否在 正在创建 bean 的集合当中;前文已经解释过 singletonsCurrentlyInCreation 这个集合现在里面存在且只有一个 user;故而也会返回true;

也就是 earlySingletonExposure 为 true, 会进入 if 条件判断,重点来了,这里是实现 Spring 循环依赖的关键代码,Spring 所谓的三级缓存闪亮登场,你会发现 这里只是把工厂对象 put 进 singletonFactories 集合,这一步也很关键

/**
 * Add the given singleton factory for building the specified singleton
 * if necessary.
 * <p>To be called for eager registration of singletons, e.g. to be able to
 * resolve circular references.
 * @param beanName the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    
    
	//singletonObjects 一级缓存
	//singletonFactories 二级缓存
	//earlySingletonObjects 三级缓存
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
    
    
		//如果 bean 存在单例池的话已经是一个完整的 bean 了,
		//也就是走完了生命周期,那就不需要后面的步骤了
		if (!this.singletonObjects.containsKey(beanName)) {
    
    
			//把工厂对象 put 到二级缓存
			this.singletonFactories.put(beanName, singletonFactory);
			//?为什么要 remove,本质上看,这三个 map 存的都是同一个对象
			//Spring 的做法是三个不能同时都存
			//如果 singletonObjects 存了,其它两个就要 remove,反之亦然
			this.earlySingletonObjects.remove(beanName);
			//无关紧要这行
			this.registeredSingletons.add(beanName);
		}
	}
}

Spring 是如何解决循环依赖的?

在这里插入图片描述
比如上面 User 和 Teacher 两个类,互相注入,默认情况下,spring 创建 bean 默认的顺序是根据字母顺序的;也就是说会先创建 Teacher–>开始 Teacher 的生命周期---->走到 Teacher 属性的注入–> 填充 User --> getBean(“user”) 获取?–>创建 User–>开始 User 的生命周期–>走到 User 属性的注入–>填充 Teacher–>getBean(“teacher”) 获取?

所以这个依赖注入会不会无限循环下去关键要看 getBean 能不能获取到,而 getBean 底层调用的就是 doGetBean 方法,这里再次贴下代码:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
    

	final String beanName = transformedBeanName(name);
	Object bean;
	// Eagerly check singleton cache for manually registered singletons.
	//第一次调用getSingleton: 因为是第一次初始化,这里 sharedInstance 显然是为 null,
	//里面的逻辑是实现循环依赖最主要的代码,后文详说
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
    
    
		....
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
	else {
    
    
		...
		try {
    
    
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
			...
			// Create bean instance.
			if (mbd.isSingleton()) {
    
    
				//第二次调用getSingleton,完成了bean的初始化
				sharedInstance = getSingleton(beanName, () -> {
    
    
					try {
    
    
						return createBean(beanName, mbd, args);
					}
					...
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
			else if (mbd.isPrototype()) {
    
    
				// It's a prototype -> create a new instance.
				...
			}
		}
		...
	}
	...
	return (T) bean;
}

毫无疑问,Spring 解决了循环依赖的问题,根据前文分析,这里 第一次调用 getSingleton 方法就起作用了,进入方法查看

@Override
@Nullable
public Object getSingleton(String beanName) {
    
    
	return getSingleton(beanName, true);
}
/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or not
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
	//从单例池当(一级缓存)中直接拿,也就是文章里面'目前'的解释
	//这也是为什么getBean("xx")能获取一个初始化好bean的根本代码
	Object singletonObject = this.singletonObjects.get(beanName);
	//比如创建了 Teacher 对象,需要注入User,那么要创建 User,接着要把 teacher 注入到 user
	//根据前文分析,创建 Teacher 对象过程中,singletonCurrentlyInCreation 存了这个beanName
	//同理,创建 User 对象过程中,singletonCurrentlyInCreation 存了 user 这个beanName
	//并且二级缓存 singletonFactory 都保存了这两个工厂对象
	//进入if分支
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    
		synchronized (this.singletonObjects) {
    
    
			//回顾一下文章上面的流程讲工厂对象那里,只把他存到了二级缓存,所以 singletonObject==nil
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
    
    
				//二级缓存中有值
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
    
    
					singletonObject = singletonFactory.getObject();
					//拿到了半成品的xbean之后,把他放到三级缓存;为什么?
					this.earlySingletonObjects.put(beanName, singletonObject);
					//然后从二级缓存清除掉x的工厂对象;为什么?
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

为什么首先是从三级缓存中取呢?

主要是为了性能,因为三级缓存中存的是一个x对象,如果能取到则不去二级找了;那二级有什么用呢?

为什么一开始要存工厂呢(二级缓存)?为什么一开始不直接存三级缓存?

工厂嘛,可以改变对象的一些状态,比如原本保存的是 use 对象工厂,但是注入的时候我需要对这个对象的属性或者外观进行改动,这个工厂就比较方便了

为什么要从二级缓存remove?

因为如果存在比较复杂的循环依赖可以提高性能;比如x,y,z相互循环依赖,那么第一次y注入x的时候从二级缓存通过工厂返回了一个x,放到了三级缓存,而第二次z注入x的时候便不需要再通过工厂去获得x对象了。因为if分支里面首先是访问三级缓存;至于remove则是为了gc吧;

FactoryBean 和 BeanFactory 的区别

public interface FactoryBean<T> {
    
    
	//从工厂中获取bean
	@Nullable
	T getObject() throws Exception;
	//获取Bean工厂创建的对象的类型
	@Nullable
	Class<?> getObjectType();
	//Bean工厂创建的对象是否是单例模式
	default boolean isSingleton() {
    
    
		return true;
	}
}

  • 他们两个都是个工厂,但FactoryBean本质上还是一个Bean,也归BeanFactory管理
  • BeanFactory是Spring容器的顶层接口,FactoryBean更类似于用户自定义的工厂接口

再次总结 Spring Bean 生命周期

1、scan,封装成beandefination对象,放入beandefination
2、遍历map
3、validate,是不是抽象啊,是不是懒加载啊,是不是prototype
4、得到 class
5、推断构造方法
5、反射,实例化对象
6、合并beandefination
7、提前暴露一个 bean工厂对象
8、填充属性,自动注入:populateBean 方法
9、执行部分 aware 接口,调用声明周期初始化回调方法(@postconstructor)
10、如果需要代理则完成代理
11、put到单例池——bean完成——存在spring容器当中

如果是 @Resource --> 调用CommonAnnotationBeanPostProcessor
如果是 @Autowire --> 调用AutowireAnnotationBeanPostProcessor

猜你喜欢

转载自blog.csdn.net/lhg_55/article/details/105371345