Spring 源码的Spring Bean 的创建过程

Spring Bean 的创建刚开始进行了一些准备工作,比如转换服务的初始化,占位符解析器的初始化, BeanDefinition 元数据的冻结等操作,都是为了在创建Bean的过程中保证 Bean 的正确的创建,接下来开始进行对 Bean 的创建进行解析。

Bean 的创建步骤

在 Spring 源码中对 Bean 的创建遵循一个步骤就是: getBean --> doGetBean --> createBean --> doCreateBean ,常规的 Bean 的创建过程都是按照这个步骤执行,然后反射实例化,属性填充,初始化,放到一级缓存中。那么非常规的有可能就不遵循这个步骤,比如 FactoryBean , InstantiationAwareBeanPostProcessor 等。

上源码:

public void preInstantiateSingletons() throws BeansException {
  if (logger.isTraceEnabled()) {
    logger.trace("Pre-instantiating singletons in " + this);
  }

  // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  // Trigger initialization of all non-lazy singleton beans...
  // 遍历所有的beanName
  for (String beanName : beanNames) {
    // 获取RootBeanDefinition 从缓存中,第一个放入缓存是在 AbstractApplicationContext#invokeBeanFactoryPostProcessors 中的getBeanNamesForType方法中
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    // 如果不是抽象的,是单例的,是非懒加载的,则进行bean的创建,否则直接跳过
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      // 是否是FactoryBean
      if (isFactoryBean(beanName)) {
        // 获取bean实例
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        // 判断获取的Bean是否是FactoryBean
        if (bean instanceof FactoryBean) {
          FactoryBean<?> factory = (FactoryBean<?>) bean;
          // 是否是饥饿初始化,默认是false
          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());
          }
          // 如果是饥饿初始化,则进行bean的创建
          if (isEagerInit) {
            getBean(beanName);
          }
        }
      }
      else {
        // 获取bean
        getBean(beanName);
      }
    }
  }

  // Trigger post-initialization callback for all applicable beans...
  // 触发 所有Bean初始化后的回调
  for (String beanName : beanNames) {
    Object singletonInstance = getSingleton(beanName);
    // 获取单例对象,如果是SmartInitializingSingleton 则调用afterSingletonsInstantiated
    // 在监听器中使用@EventListener注解标记的方法就是在这个方法中进行监听器的添加的,会创建一个监听器的适配器
    // 调用类为 EventListenerMethodProcessor
    if (singletonInstance instanceof SmartInitializingSingleton) {
      SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
      // 权限检查
      if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
          smartSingleton.afterSingletonsInstantiated();
          return null;
        }, getAccessControlContext());
      }
      else {
        smartSingleton.afterSingletonsInstantiated();
      }
    }
  }
}

通过源码可以知道, Spring 前期在进行 XML 进行 loadBeanDefinitions 加载或者 BeanFactoryPostProcessor 子类 BeanDefinitionRegistryPostProcessor 的实现类 ConfigurationClassPostProcessor 注解解析 出来的 BeanDefinition 放入两个集合 BeanDefinitionMap 和 BeanDefinitionNames ,这里遍历的是 BeanDefinitionNames 这个集合,存放的是 beanName 。

首先是进行了BeanDefinition的合并处理,最终返回的全是RootBeanDefinition,进入源码可以看到这里是从缓存中获取的,如果有则直接取出来,否则再去解析。

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
  // Quick check on the concurrent map first, with minimal locking.
  // 从缓存中获取
  RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
  if (mbd != null && !mbd.stale) {
    return mbd;
  }
  return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

那么第一次进行调用时什么地方呢?是在进行 BeanFactoryPostProcessor 的执行和解析时调用的,在解析 BeanFactoryPostProcessor 时调用了 getBeanNamesForType 方法,然后调用 doGetBeanNamesForType 时进行了 BeanDefinitionNames 集合的遍历合并 Bean :

private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
  List<String> result = new ArrayList<>();
  // Check all bean definitions.
  // 遍历所有的BeanDefinitionNames集合
  for (String beanName : this.beanDefinitionNames) {
    // Only consider bean as eligible if the bean name is not defined as alias for some other bean.
    if (!isAlias(beanName)) {
      try {
        // 从本地缓存中获取合并的BeanDefinition
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // Only check bean definition if it is complete.
        if (!mbd.isAbstract() && (allowEagerInit ||
                                  (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                                  !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
          // 是否是FactoryBean
          boolean isFactoryBean = isFactoryBean(beanName, mbd);
          BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
          boolean matchFound = false;
          boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
          boolean isNonLazyDecorat
            // 省略代码....
        }
      }
    }
  }

所以在执行 preInstantiateSingletons 预实例化单例时获取的 RootBeanDefinition 基本是从缓存中获取的。

接着是判断如果是单例的并且不是抽象的,不是懒加载的,那么就进行 Bean 的创建,然后又判断是否是 FactoryBean ,如果是那么就进行下一步逻辑。

FactoryBean 是什么?

FactoryBean 是用来创建 Bean 对象的,他是一个接口,方法:

  • getObject 获取bean对象
  • getObjectType 获取bean的类型
  • isSingleton 是否是单例的,默认是 true

在创建对象时,你可以直接在 getObject 方法中进行 new ,或者反射,或者是其他都可以,非常的灵活。接下来使用 FactoryBean 进行自定义的 Bean 的创建。

定义一个 FactoryBean 的实现类:

/**
 * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
 * @since 1.0
 **/
public class MyFactoryBean implements FactoryBean<MyUser> {

	@Override
	public MyUser getObject() throws Exception {
      	// 直接new一个对象
		return new MyUser();
	}

	@Override
	public Class<?> getObjectType() {
		return MyUser.class;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}
}

定义 MyUser

/**
 * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
 * @since 1.0
 **/
public class MyUser {
}

xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
   <bean id="myFactoryBean" class="com.redwinter.selffactorybean.MyFactoryBean"/>
</beans>

测试类:

/**
 * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
 * @since 1.0
 **/
public class FactoryBeanTest {

	@Test
	public void test(){
		MyClassPathXmlApplicationContext context = new MyClassPathXmlApplicationContext("spring-factory.xml");

		Object myFactoryBean =  context.getBean("myFactoryBean");
		System.out.println(myFactoryBean);

		Object myFactoryBean2 =  context.getBean("&myFactoryBean");
		System.out.println(myFactoryBean2);

	}
}

输出:

com.redwinter.test.selffactorybean.MyUser@2d554825
com.redwinter.test.selffactorybean.MyFactoryBean@68837a77

这里可以看到 FactoryBean 创建 Bean 的时候, xml 注册的是一个 FactoryBean 的实现,但是获取出来又是具体的 MyUser 对象,这里 Spring 使用了懒加载的机制,在 Spring 对 Bean 进行初始化时,实际上只将 FactoryBean 的实现类注册到了 Spring 容器中,当我们需要使用的时候,才去判断,如果是 FactoryBean 类型的,那么就去调用 getObject 方法去创建对象。如果是第二次去获取 Bean ,那么是从缓存中获取的,如果是获取 & 前缀的 Bean ,那就直接返回。

protected Object getObjectForBeanInstance(
  Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

  // Don't let calling code try to dereference the factory if the bean isn't a factory.
  // 判断是否是&前缀标识
  if (BeanFactoryUtils.isFactoryDereference(name)) {
    if (beanInstance instanceof NullBean) {
      return beanInstance;
    }
    if (!(beanInstance instanceof FactoryBean)) {
      throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
    }
    if (mbd != null) {
      mbd.isFactoryBean = true;
    }
    return beanInstance;
  }

  // Now we have the bean instance, which may be a normal bean or a FactoryBean.
  // If it's a FactoryBean, we use it to create a bean instance, unless the
  // caller actually wants a reference to the factory.
  if (!(beanInstance instanceof FactoryBean)) {
    return beanInstance;
  }

  Object object = null;
  if (mbd != null) {
    mbd.isFactoryBean = true;
  }
  else {
    // 从缓存中获取
    object = getCachedObjectForFactoryBean(beanName);
  }
  if (object == null) {
    // Return bean instance from factory.
    FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    // Caches object obtained from FactoryBean if it is a singleton.
    if (mbd == null && containsBeanDefinition(beanName)) {
      mbd = getMergedLocalBeanDefinition(beanName);
    }
    // 判断是否是合成的Bean,是否是应用程序本身设置的,比如某些aop 就是合成的Bean
    boolean synthetic = (mbd != null && mbd.isSynthetic());
    // 执行getObject方法获取Bean
    object = getObjectFromFactoryBean(factory, beanName, !synthetic);
  }
  return object;
}

BeanFactory 和FactoryBean 的区别?

根据前面的文章介绍,我们知道 BeanFactory 是一个 Bean 的创建工厂,比如 AbstractApplicationContext 就是 BeanFactory 的实现类,这个类就是用来创建 Bean 的,创建出来的 Bean 放在缓存中。而 FactoryBean 就是 Bean 实例,是由 BeanFactory 创建的,并且 FactoryBean 也是用来创建 Bean 对象,使用 getObject 方法进行创建,也是会放在缓存中供下次直接获取,而且如果在使用时需要使用 FactoryBean 的实例时需要以 & 前缀才能获取到,比如 getBean("&myFactoryBean"); 如果是获取通过 getObject 方法创建的对象时,就不需要添加 & 前缀,比如 getBean("myFactoryBean"); 总结一下:

相同点:

  • 都是用来创建对象的
  • 都是创建出来之后放入缓存中供下次直接使用

不同点:

  • BeanFactory 是一个对象创建工厂,而 FactoryBean 是一个 Bean 实例
  • BeanFactory 创建的对象一般来说都是使用反射调用构造函数创建的,而 FactoryBean 创建对象是调用 getObject 方法创建,并且创建方式不一定是通过反射,可以是直接 new 对象或者其他方式
  • FactoryBean 在获取对象时,可以获取到两个对象,一个是存放在 BeanFactory 创建的缓存中,通过 &beanName 获取的 FactoryBean 的实现类对象,一个是调用 getObject 创建的,通过 beanName 获取的具体对象。

Bean 的创建过程非常复杂,下一篇继续。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值