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