spring bean学习总结

262 阅读6分钟

Spring Bean学习总结

BeanDefinition:定义 Bean的作用范围、角色、依赖、懒加载等与 Spring容器运行和管理Bean息息相关的属性,以达到对Bean的Spring特性的定制,是Spring Bean描述定义信息的核心接口类。

1、Bean的注册

在使用Spring时,我们可以通过获取一个应用上下文(ApplicationContext)对象来操作各种Bean。如果使用基于注解的配置方式,可以使用AnnotationConfigApplicationContext来初始化容器上下文对象。

AnnotationConfigApplicationContext主要构造方法:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
   this();
  //根据java配置类注册bean
   register(componentClasses);
   refresh();
}

public AnnotationConfigApplicationContext(String... basePackages) {
   this();
  //根据包路径扫描
   scan(basePackages);
   refresh();
}

以register()方法为例进行讨论:

@Override
public void register(Class<?>... componentClasses) {
   Assert.notEmpty(componentClasses, "At least one component class must be specified");
   this.reader.register(componentClasses);
}

在方法内使用了AnnotatedBeanDefinitionReader工具类来完成bean的注册。在this.reader.register()方法中,遍历所有传入的componentClasses注解类,然后通过registerBean()完成注册。

public void register(Class<?>... componentClasses) {
   for (Class<?> componentClass : componentClasses) {
      registerBean(componentClass);
   }
}
public void registerBean(Class<?> beanClass) {
   doRegisterBean(beanClass, null, null, null, null);
}

registerBean方法内继续调用doRegisterBean:

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
      @Nullable BeanDefinitionCustomizer[] customizers) {
   //将注解类转换成一个BeanDefinition
   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
   //...
   //获取Bean的作用域元数据,解析Bean作用域
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   //将Bean作用域写回BeanDefinition
   abd.setScope(scopeMetadata.getScopeName());
   //生成beanName
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

   //解析@Lazy、@Primary等注解
   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
   //...
   //注册Bean的定义
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

最后,通过registerBeanDefinition()方法完成Bean的注册,该方法内部通过ListableBeanFactory的实现类DefaultListableBeanFactory将Bean定义信息注册到Spring IoC容器中。

基本流程:

graph LR;
A[构建BeanDefinition]-->B[设置BeanDefinition属性]
B-->C[注册BeanDefinition]

2、Bean的运行实现

将Bean的定义加载到了容器中后,还需要调用refresh()方法刷新容器。这里只关注finishBeanFactoryInitialization方法

public void refresh() throws BeansException, IllegalStateException {
        try {
         //...
         // 初始化所有的单例Bean
         finishBeanFactoryInitialization(beanFactory);
         //...
        }
      }
   }
}

finishBeanFactoryInitialization()方法才是真正的完成Bean实例化的入口。在这个方法中,完成Bean的实例化代码实际上位于它的子类DefaultListableBeanFactory中:

public void preInstantiateSingletons() throws BeansException {
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   //触发所有非懒加载的单例Bean的初始化操作
   for (String beanName : beanNames) {
          //...
          getBean(beanName);
          //...
   }
}

进入到getBean()方法,一路跟踪源码到doCreateBean方法:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

      //1. 实例化Bean
      instanceWrapper = createBeanInstance(beanName, mbd, args);
      //2. 属性注入
      populateBean(beanName, mbd, instanceWrapper);
      //3. 初始化Bean
      exposedObject = initializeBean(beanName, exposedObject, mbd);
      //...
      return exposedObject;
}

该方法包含三个核心方法:

  • createBeanInstance():实例化,通过构造方法反射创建一个bean实例对象,实例化所得到的对象,是“不完整”的对象;

  • populateBean():属性填充,实现属性的自动注入,包含byName、byType类型的自动装配,以及基于@Autowired、@Value注解的属性设值。执行完这一步之后,可以说Bean已经是完整的了。

  • initializeBean():初始化,在属性填充之后,执行Aware扩展以及Bean后处理器和init初始化方法等。

单例对象的初始化步骤:

graph LR;
A[createBeanInstance:实例化]-->B[populateBean:属性填充]
B-->C[initializeBean:初始化]

3、创建Bean

Spring为开发人员提供了三种不同的依赖注入类型,分别是字段注入、构造器注入和Setter方法注入。但是它们的注入顺序不一致,因为Spring在实例化Bean时要先找到合适的构造方法,并准备构造方法的参数等数据,再进行实例化。在实例化后产生对象时才能对当前对象的属性进行装载注入(如反射调用方法、为属性赋值等);

查看createBeanInstance()方法:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // 再次解析BeanDefinition的class,确保class已经被解析
   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());
   }
   
   // 1、如果提供了Supplier,通过Supplier产生对象
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // 2、如果有工厂方法,使用工厂方法产生对象  
   // 在@Configration配置@Bean的方法,也会被解析为FactoryMethod
   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // ...
   // 3、推断构造方法
   // 3.1 执行后置处理器,获取候选构造方法
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   // 3.2 需要自动注入的构造函数
   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);
   }

   // 3.3 使用默认无参构造函数创建对象
   return instantiateBean(beanName, mbd);
}

具体逻辑是:

1.先判断是否提供了Supplier,如果提供,则通过Supplier产生对象。

2.再判断是否提供工厂方法,如果提供,则使用工厂方法产生对象。

3.如果都没提供,需要进行构造方法的推断,逻辑为:

  • 如果没有,Spring默认选择无参构造方法;
  • 如果有,且有@Autowired(required=true)的构造方法,就会选择该构造方法;
    • 如果有,但是没有@Autowired(required=true)的构造方法,Spring会从所有加了@Autowired的构造方法中,根据构造器参数个数、类型匹配程度等综合打分,选择一个匹配参数最多,类型最准确的构造方法。
    • 如果仅有一个构造方法,会直接使用该构造方法(如果构造方法有参数,会自动注入依赖参数)
    • 如果有多个构造参数,会判断有没有加了@Autowired注解的构造参数:

Bean实例化流程.png

4、Bean的属性注入

本阶段完成了Spring的核心功能之一:依赖注入,包括自动注入@Autowired注入@Resource注入等。

属性注入的前提是当前对象已经完成了实例化,这样才能注入属性,因为注入属性的前提是有真正的targetObject。

在创建 Bean 实例后调用了 populateBean 方法。属性注入就是通过populateBean方法开始的。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   //如果实例为null,并且属性值不为空,则不能注入,抛出异常;如果属性值为空,则跳出当前方法
   if (bw == null) {
      if (mbd.hasPropertyValues()) {
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
         // Skip property population phase for null instance.
         return;
      }
   }

   // 如果当前bean不是合成的bean,并且在当前工厂中注册了InstantiationAwareBeanPostProcessor后处理器,则顺序调用该类型Bean后处理器修改bean的状态,其中任意一个发生问题,则方法不再继续
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
           	// 实例化后执行, 这里如果返回 false 会跳过依赖注入阶段
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               return;
            }
         }
      }
   }

   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
   
   // 获取bean的注入类型
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   // 只处理当前bean按类型自动注入和按名称自动注入
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      //如果是按名称注入,则直接通过getBean方法获取这些bean,然后注入,添加属性信息并注册当前依赖的Bean到BeanFactory中
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
         autowireByName(beanName, mbd, bw, newPvs);
      }
      // 按类型获取并解决依赖,调用resolveDependency来处理,在获取对象的值后调用类型转换处理返回值,并且添加到属性信息
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
         autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
     	//调用bean后处理器的postProcessProperties方法,用来解析@Autowired、@Value、@Resource等注解注入属性
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            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;
         }
      }
   }
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }

   if (pvs != null) {
      //解析转换所有属性信息,为这个bean实例装入所有属性
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

5、Bean的初始化

该阶段主要做bean的初始化操作,包括:回调Aware接口回调初始化方法生成代理对象等。

查看initializeBean方法:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   // 1、回调Aware接口的实现方法,注入BeanName、ClassLoader和BeanFactory
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   //2、调用Bean后处理器,初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   //3、调用初始化方法
   try {
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
  
   //4、调用Bean后处理器,初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强
   if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

查看invokeInitMethods方法:

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {
	 //1. 调用InitializingBean的afterPropertiesSet方法
   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
         logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
         try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
               ((InitializingBean) bean).afterPropertiesSet();
               return null;
            }, getAccessControlContext());
         }
         catch (PrivilegedActionException pae) {
            throw pae.getException();
         }
      }
      else {
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }
	 
   //2. 调用自定义初始化方法
   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

由源码分析可知,构造函数 > @PostConstruct > InitializingBean > 自定义init-method

在初始化完成后,bean会被放到单例池中,后续有使用到该bean的地方,直接从单例池中获取,不会再次创建bean(仅单例)。

6、Bean的销毁

回doGetBean方法,在方法的最后:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
    //...
    
    // Register bean as disposable.
    try {
       registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
       throw new BeanCreationException(
             mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

在创建bean的时候,会判断如果bean是DisposableBeanAutoCloseable的子类,或者有 destroy-method等,会注册为可销毁的bean,在容器关闭时,调用对应的方法进行bean的销毁。