第11节 Spring源码之 Bean 创建流程

106 阅读8分钟

  Spring 源码中 Bean 的创建应该是其核心流程之一,但是这个流程也是极其复杂的,所以还是先有个整体概念,然后再分步骤解析其中的逻辑。

  • Bean 创建核心方法链路

Spring源码1-getBean.drawio.png

getBean 是获取容器中 bean 实例的入口方法,Spring 容器中上层调用 getBean 的入口很多,这里就不一一列举。

  Bean 的创建流程非常复杂且庞大,不太好做笔记,所以本文会围绕上面的图中流程来展开记录

一、Spring 中有哪几种方式可以完成bean的实例化

1. 通过实现 InstantiationAwareBeanPostProcessor 接口来实例化

通过实现 InstantiationAwareBeanPostProcessor 接口 ,然后在postProcessBeforeInstantiation 方法中利用 cglib 代理的方式完成 Bean 的创建,该方式创建的 Bean 对象是没有被实例化的InstantiationAwareBeanPostProcessor 接口也是BeanPostProcessor 的子接口。该案例中只是我们自己通过这种方式来模拟 Spring 容器的实现,Spring 容器内部中只有在AOP的时候才会用这种方法创建 Bean。

image.png

  • 实现了 InstantiationAwareBeanPostProcessor 接口的类方法的调用关系
public class House {
   private String address;

   public String getAddress() {
      return address;
   }

   public void setAddress(String address) {
      this.address = address;
   }
}
public class CusInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

   // BeanPostProcessor 接口的方法
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("CCCC--执行了 BeanPostProcessor 的 postProcessBeforeInitialization 方法,说明属性填充已完成");
      return bean;
   }

   // BeanPostProcessor 接口的方法
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
      return bean;
   }

   /**
    * 在bean实例化之后调用,即创建bean对象之前调用
    */
   @Override
   public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
      System.out.println("AAAA--执行了 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法");
      return null;
   }

   /**
    * 在bean实例化之后调用,填充属性值之前调用
    * (1) 该方法返回 true 时会执行 bean 对象属性填充逻辑,如果返回 false ,不执行属性填充逻辑逻辑
    */
   @Override
   public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
      System.out.println("BBBB--执行了 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法");
      return true;
   }

   @Override
   public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
      return pvs;
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="house" class="com.sff.demo.createBean.bean.House">
      <property name="address" value="小县城"></property>
   </bean>
   <bean class="com.sff.demo.createBean.CusInstantiationAwareBeanPostProcessor"/>

</beans>

image.png

从运行结果来看,InstantiationAwareBeanPostProcessor的方法执行时机比BeanPostProcessor的时机更早。如下图所示:

Spring源码1-InstantiationAwareBeanPostProcessor.drawio.png

所以此时想要完成 Bean 的实例化创建,那么只能在 InstantiationAwareBeanPostProcessor 中的 postProcessBeforeInstantiation 方法使用 cglib 动态代理来实现bean的创建。改造代码逻辑如下:

public class CusInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

   // BeanPostProcessor 接口的方法
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("CCCC--执行了 BeanPostProcessor 的 postProcessBeforeInitialization 方法,说明属性填充已完成");
      return bean;
   }

   // BeanPostProcessor 接口的方法
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
      return bean;
   }

   /**
    * 在bean实例化之后调用,即创建bean对象完成后调用
    */
   @Override
   public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
      System.out.println("AAAA--执行了 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法");
      if (!beanClass.equals(House.class)) {
         return null;
      }
      // 在该方法中实现 cglib 代理的方式实现完成对象的创建,此时 Spring 容器在实例化 bean 时
      Enhancer en = new Enhancer();
      en.setSuperclass(beanClass);
      // 设置回调函数
      en.setCallback(new MyMethodInterceptor());
      // 返回代理对象
      House house = (House) en.create();
      return house;
   }

   private class MyMethodInterceptor implements MethodInterceptor {
      /**
       * @param o           表示增强的对象,即实现这个接口类的一个对象
       * @param method      表示要拦截的方法
       * @param objects     表示被拦截的方法的参数
       * @param methodProxy 表示要触发父类的方法对象
       * @return
       */
      @Override
      public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
         // cglib 代理调用 invoke 和 invokeSuper 方法的实现方式是不同的
         Object returnValue = methodProxy.invokeSuper(o, objects);
         return returnValue;
      }
   }

   /**
    * 在bean实例化之后调用,填充属性值之前调用
    * (1) 该方法返回 true 时会执行 bean 对象属性填充逻辑,如果返回 false ,不执行属性填充逻辑逻辑
    */
   @Override
   public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
      System.out.println("BBBB--执行了 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法");
      return true;
   }

   @Override
   public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
      return pvs;
   }
}

image.png

从运行结果来看,此时虽然在xml文件中配置了该 bean 的 address 属性值,但是实际输出bean的属性值为NULL。说明该种方法创建的bean对象没有完成初始化操作,如果要完成初始化该怎么办?

  • BeanPostProcessorpostProcessAfterInitialization 方法中自定义填充属性逻辑即可完成
// BeanPostProcessor 接口的方法
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   System.out.println("DDDD--执行了 BeanPostProcessor 的 postProcessAfterInitialization 方法,说明属性填充已完成");
   if (bean instanceof House) {
      House h = (House) bean;
      h.setAddress("乡村");
      bean = h;
   }
   return bean;
}

image.png

2. 通过 Supplier 来实例化

该方式其实就是 Spring 利用了 Supplier 函数式接口,然后进行回调,在回调方法中实例化你需要的 bean

  • 定义创建bean的方法
public class CreateBeanBySupplier {
   public static House getBean() {
      House house = new House();
      house.setAddress("别墅");
      return house;
   }
}
  • 实现 BeanFactoryPostProcessor 接口
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

      BeanDefinition beanDefinition = beanFactory.getBeanDefinition("house");
      GenericBeanDefinition house = (GenericBeanDefinition) beanDefinition;
      // 设置回调函数
      house.setInstanceSupplier(CreateBeanBySupplier::getBean);
   }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="house" class="com.sff.demo.createBean.bean.House">
   </bean>
   <bean class="com.sff.demo.createBean.SupplierBeanFactoryPostProcessor"/>

</beans>

image.png

通过该方式来实例化的bean,会按照bean生命周期走完所有流程方法。如果此时你在 xml 文件里直接注入属性的话,xml 文件中的属性值会覆盖掉代码中设置的属性值

<bean id="house" class="com.sff.demo.createBean.bean.House">
   <property name="address" value="小县城"></property>
</bean>

3. 通过FactoryBean来实例化

public class HourFactoryBean implements FactoryBean<House> {
   
   @Override
   public House getObject() throws Exception {
      House house = new House();
      house.setAddress("西安");
      return house;
   }

   @Override
   public Class<?> getObjectType() {
      return House.class;
   }
}
<bean name="car" class="com.sff.demo.createBean.HourFactoryBean"></bean>

4. 通过工厂方法来实例化

// 简单工厂
public class CarFactory {

   public Car getCar() {
      Car car = new Car();
      car.setCarName("宝马");
      return car;
   }
}
<!--工厂方法注入-->
<bean id="carFactory" class="com.sff.demo.bean.CarFactory"/>
<bean id="bwmCar" factory-bean="carFactory" factory-method="getCar"/>

总结: 通过 自定义的工厂方法 、FactoryBeangetObject() 方法、@Bean注解方式实例化的 bean 对象走的都是 instantiateUsingFactoryMethod() 方法来统一实例化的。

5. 通过反射来实例化

除了上面几种方式实例化 bean 外,其他的都是通过反射来实例化的

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      if (System.getSecurityManager() != null) {
         beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this), getAccessControlContext());
      } else {

         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
      }

      // bean 的包装类,主要用于 bean 属性类型的解析
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);

      return bw;
   } catch (Throwable ex) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
}

image.png

二、Spring 中是如何解析 @PostConstruct 、@PreDestroy、 @Resource@Autowired 和 @Value 注解的?

为什么要把这把这个五个注解的解析逻辑放在一起讲?因为它们的解析入口方法都是同一个方法,只是底层通过不同的 BeanPostProcessor来处理的。

Spring源码1-getBean.drawio.png

  • 该入口方法就是:applyMergedBeanDefinitionPostProcessors()
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

可以看到该方法处理的就是 MergedBeanDefinitionPostProcessor 处理器,这个处理器是干啥呢?它是 BeanPostProcessor 的子接口,其中有三个和本文相关的实现类:CommonAnnotationBeanPostProcessorInitDestroyAnnotationBeanPostProcessorAutowiredAnnotationBeanPostProcessor

image.png

MergedBeanDefinitionPostProcessor 接口中定义了 postProcessMergedBeanDefinition 方法,该方法在入口方法: applyMergedBeanDefinitionPostProcessors() 中调用。

public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {

   void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);

}

先给结论:

  • CommonAnnotationBeanPostProcessor:该处理器中完成了 @Resource 注解的解析
  • InitDestroyAnnotationBeanPostProcessor:该处理器中完成了 @PostConstruct 和 @PreDestroy 注解的解析
  • AutowiredAnnotationBeanPostProcessor:该处理器中完成了 @Autowired 和 @Value 注解的解析

1. CommonAnnotationBeanPostProcessor 处理器

CommonAnnotationBeanPostProcessorpostProcessMergedBeanDefinition() 方法中调用了父类 InitDestroyAnnotationBeanPostProcessorpostProcessMergedBeanDefinition() 方法,在该方法中处理了 @PostConstruct@PreDestroy 注解。

public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {

    /**
     * 该方法是在 CommonAnnotationBeanPostProcessor 对象注入容器时通过反射调用构造器时调用,此时设置了 @PostConstruct @PreDestroy 注解类型
     */
    public CommonAnnotationBeanPostProcessor() {
       setOrder(Ordered.LOWEST_PRECEDENCE - 3);
       setInitAnnotationType(PostConstruct.class);
       setDestroyAnnotationType(PreDestroy.class);
       ignoreResourceType("javax.xml.ws.WebServiceContext");
    }

    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
       // 处理 @PostConstruct 、@PreDestroy 注解
       super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
       // 处理 @Resource 注解,找出 beanType 所有被 @Resource 标记的字段和方法封装到 InjectionMetadata 中
       InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
       metadata.checkConfigMembers(beanDefinition);
    }
}

2. AutowiredAnnotationBeanPostProcessor 处理器

    /**
     * 注解标识的方法、字段filed 转换成 InjectionMetadata 对象
     * (1) InjectionMetadata 这个类非常重要,到了此处 @Autowired 注解含义已经没有了,完全被解析成 InjectionMetadata 这个元数据对象
     * (2) InjectionMetadata 持有 targetClass、Collection<InjectedElement> injectedElements 等两个重要属性
     * (3) 其中 InjectedElement 这个抽象类最重要的两个实现为:AutowiredFieldElement 和 AutowiredMethodElement
    */
    private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);

    // 设置该处理器能够解析的注解类型
    public AutowiredAnnotationBeanPostProcessor() {
        this.autowiredAnnotationTypes.add(Autowired.class);
        this.autowiredAnnotationTypes.add(Value.class);
   
        this.autowiredAnnotationTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
    }

/**
 * (1) 解析@Autowired @Value 注解
 * (2) 把注解信息转换为 InjectionMetadata 然后缓存到上面的 injectionMetadataCache 里面
 */
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}

以上 BeanPostProcessor 在解析 @PostConstruct 、@PreDestroy、 @Resource@Autowired 和 @Value 时,最终都是将解析结果封装成了 InjectionMetadata 对象

public class InjectionMetadata {

   private final Class<?> targetClass;

   private final Collection<InjectedElement> injectedElements;

   private volatile Set<InjectedElement> checkedElements;

   // 省略部分代码 ...
}   

在后续流程当中又会将 InjectionMetadata 解析,然后赋值给对应 bean 的属性上,该操作发生在 populateBean() 方法中。

三、Spring 中 Bean 的属性填充 populateBean() 方法

Spring源码1-populateBean.drawio.png

四、Spring 中 Bean 属性填充完成后执行 initializeBean() 方法

该方法的主要功能是:依次调用 Aware接口相关方法、BeanPostProcessor 前置处理器、init-method、调 BeanPostProcessor 后置处理器

initializeBean (1).jpg

(1) 为什么这里只调用了 BeanNameAwareBeanClassLoaderAwareBeanFactoryAware 三个接口的方法?

obtainFreshBeanFactory() 获取容器对象 BeanFactory 时调用了构造方法 AbstractAutowireCapableBeanFactory() 中对该三个 Aware 接口进行了忽略设置,所以才会在 initializeBean() 中对这三个接口方法进行单独调用。

public AbstractAutowireCapableBeanFactory() {
   super();
   ignoreDependencyInterface(BeanNameAware.class);
   ignoreDependencyInterface(BeanFactoryAware.class);
   ignoreDependencyInterface(BeanClassLoaderAware.class);
}

剩下的一些 Aware 接口会在 BeanPostProcessorpostProcessBeforeInitialization() 方法中设置到容器中去

public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
   AccessControlContext acc = null;

   if (System.getSecurityManager() != null &&
         (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
               bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
               bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
   }

   if (acc != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareInterfaces(bean);
         return null;
      }, acc);
   }
   else {
      invokeAwareInterfaces(bean);
   }

   return bean;
}

private void invokeAwareInterfaces(Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
         ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
         ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
      }
      if (bean instanceof ResourceLoaderAware) {
         ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
         ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
         ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
         ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
   }
}
  • Aware 接口到底有什么用?

当对 Sprig 容器创建的 bean 对象在进行一些逻辑操作时,需要使用 Spring 容器的其他对象,此时就可以将该 bean 对象标记成 Aware 接口的实现类,比如实际开发中经常使用的 ApplicationContextAware 接口

五、Spring 中 Bean 的生命周期是什么?

Spring源码1-bean生命周期.drawio.png

在问题一中所说的bean的几种创建方式,其实就是生命周期中 bean实例化 的具体实现方式,这张图只是简单的描述了 bean 生命周期的脉络,下面这张图将详细的描述每个环境具体的操作:

bean的整个加载流程.jpg