JAVA 开发微指南

读完需要

34

分钟

速读仅需 12 分钟

/ 前言 /

在之前的文章中,我们介绍了 Bean 的核心概念、Bean 定义的解析过程以及 Bean 创建的准备工作。在今天的文章中,我们将深入探讨 Bean 的创建过程,并主要讲解 createBean 方法的实现。在这个过程中,我们将了解 Bean 的实例化、属性注入、初始化和销毁等步骤,以及各个步骤的具体实现细节。通过本文的学习,读者将能够更深入地理解 Spring 框架中 Bean 的创建过程,从而为后续的学习和实践打下坚实的基础。好了,我们开始!

/ createBean /

前面我们说过,最开始的 bean 定义(合并后的),解析类的元数据时,用到的是 ASM 技术并不会真正开始解析 class 文件,所以也只是提取出来 bean 的 name 值作为 beanClass 属性,知道这个前提,那么这一步就好说了,下面是他的源码:

  @Override  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)      throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd; // 马上就要实例化Bean了,确保beanClass被加载了 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 { Object beanInstance = doCreateBean(beanName, mbdToUse, args); ...... return beanInstance; } }


  1. resolveBeanClass:真正的开始加载 bean。

  2. mbdToUse.prepareMethodOverrides();和@lookUp 注解有关系,不看

  3. resolveBeforeInstantiation:实例化前的 BeanPostProcessors,如果初始化了那么就返回了,不走其他创建逻辑了。

  4. doCreateBean:正常开始实例化、初始化 bean。

1


   

resolveBeanClass

如果当前 bean 被加载了,那么直接返回了,如果没加载那么开始解析当前 bean

  @Nullable  protected Class<?> resolveBeanClass(RootBeanDefinition mbd, String beanName, Class<?>... typesToMatch)      throws CannotLoadBeanClassException {
try { // 如果beanClass被加载了 if (mbd.hasBeanClass()) { return mbd.getBeanClass(); }
// 如果beanClass没有被加载 if (System.getSecurityManager() != null) { return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); } else { return doResolveBeanClass(mbd, typesToMatch); } } }

是否已经加载的判断依据就是我说的,是否是 class,正常下我们的 beanClass 为字符串,也就是 beanname,看下源码:

public boolean hasBeanClass() {    return (this.beanClass instanceof Class);  }


1.1


   

doResolveBeanClass

真正开始加载 class,如果需要加载 class 那肯定离不开类加载器,看下源码:

  @Nullable  private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch)      throws ClassNotFoundException {
ClassLoader beanClassLoader = getBeanClassLoader(); ClassLoader dynamicLoader = beanClassLoader; boolean freshResolve = false;
if (!ObjectUtils.isEmpty(typesToMatch)) { // When just doing type checks (i.e. not creating an actual instance yet), // use the specified temporary class loader (e.g. in a weaving scenario). ClassLoader tempClassLoader = getTempClassLoader(); if (tempClassLoader != null) { dynamicLoader = tempClassLoader; freshResolve = true; if (tempClassLoader instanceof DecoratingClassLoader) { DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader; for (Class<?> typeToMatch : typesToMatch) { dcl.excludeClass(typeToMatch.getName()); } } } }
String className = mbd.getBeanClassName(); if (className != null) { // 解析Spring表达式,有可能直接返回了一个Class对象 Object evaluated = evaluateBeanDefinitionString(className, mbd); if (!className.equals(evaluated)) { // A dynamically resolved expression, supported as of 4.2... if (evaluated instanceof Class) { return (Class<?>) evaluated; } else if (evaluated instanceof String) { className = (String) evaluated; freshResolve = true; } else { throw new IllegalStateException("Invalid class name expression result: " + evaluated); } } if (freshResolve) { // When resolving against a temporary class loader, exit early in order // to avoid storing the resolved Class in the bean definition. if (dynamicLoader != null) { try { return dynamicLoader.loadClass(className); } catch (ClassNotFoundException ex) { if (logger.isTraceEnabled()) { logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex); } } } return ClassUtils.forName(className, dynamicLoader); } }
// Resolve regularly, caching the result in the BeanDefinition... return mbd.resolveBeanClass(beanClassLoader); }


我们自己的 bean 走不了这么多逻辑,我们既没有传 typesToMatch,也没有写 Spring 表达式,所以就是拿了一个类加载器和使用类加载器加载 class,如果我们没有自定义类加载器那么使用默认的,看下源码:

  @Nullable  public static ClassLoader getDefaultClassLoader() {    ClassLoader cl = null;
// 优先获取线程中的类加载器 try { cl = Thread.currentThread().getContextClassLoader(); } catch (Throwable ex) { // Cannot access thread context ClassLoader - falling back... }
// 线程中类加载器为null的情况下,获取加载ClassUtils类的类加载器 if (cl == null) { // No thread context class loader -> use class loader of this class. cl = ClassUtils.class.getClassLoader(); if (cl == null) { // getClassLoader() returning null indicates the bootstrap ClassLoader // 加入ClassUtils是被Bootstrap类加载器加载的,则获取系统类加载器 try { cl = ClassLoader.getSystemClassLoader(); } catch (Throwable ex) { // Cannot access system ClassLoader - oh well, maybe the caller can live with null... } } } return cl; }


  1. 优先获取线程中的类加载器

  2. 线程中类加载器为 null 的情况下,获取加载 ClassUtils 类的类加载器,这里 Spring 注意到了 java 的 boostrap 加载器,所以会有为 null 的情况

  3. 如果为 null,那么使用 ClassUtils 当前工具类使用的是哪个加载器

  4. 假如 ClassUtils 是被 Bootstrap 类加载器加载的,则获取系统类加载器


  public Class<?> resolveBeanClass(@Nullable ClassLoader classLoader) throws ClassNotFoundException {    String className = getBeanClassName();    if (className == null) {      return null;    }    Class<?> resolvedClass = ClassUtils.forName(className, classLoader);    this.beanClass = resolvedClass;    return resolvedClass;  }
  public String getBeanClassName() {    Object beanClassObject = this.beanClass;    if (beanClassObject instanceof Class) {      return ((Class<?>) beanClassObject).getName();    }    else {      return (String) beanClassObject;    }  }

通过这一步也可以看出 bean 定义中最初的 beanClass 属性,都是 String 类型的 beanname

2


   

resolveBeforeInstantiation

这一步走的是实例化前的工作,当然如果你想在这一步中直接返回实体类也可,而且最离谱的是 Spring 并没有校验你返回的类是否是当前 beanname 的类,可以看下源码:

  @Nullable  protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {    Object bean = null;    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {      // Make sure bean class is actually resolved at this point.      // synthetic表示合成,如果某些Bean式合成的,那么则不会经过BeanPostProcessor的处理      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {        Class<?> targetType = determineTargetType(beanName, mbd);        if (targetType != null) {          bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);          if (bean != null) {            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);          }        }      }      mbd.beforeInstantiationResolved = (bean != null);    }    return bean;  }


  1. hasInstantiationAwareBeanPostProcessors:直接从缓存 list 中获取有关实例化的 BeanPostProcessors,这里是一个优化,要不然每次获取有关实例化的 BeanPostProcessors 都是遍历整个 BeanPostProcessors 再加个校验

  2. determineTargetType:获取类

  3. applyBeanPostProcessorsBeforeInstantiation:执行 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 的方法,该方法可以返回 bean。

  4. postProcessAfterInstantiation:执行 BeanPostProcessor 的 postProcessAfterInstantiation 的方法,正常我们的 bean 不会走到这里,因为实例化前根本没有创建出来 bean,所以也就是 bean != null 一直为 false

当然除非你自己写一个 InstantiationAwareBeanPostProcessors,其实真没看见这么玩的,主要是没有啥意义,比如这样:

@Componentpublic class MyInstantiationAwareBeanPostProcessors implements InstantiationAwareBeanPostProcessor {
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { if (beanName.equals("userService")) { System.out.println("MyInstantiationAwareBeanPostProcessors.postProcessBeforeInstantiation"); return new First(); } return null; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (beanName.equals("userService")) { System.out.println("MyInstantiationAwareBeanPostProcessors.postProcessAfterInitialization"); return new Second(); } return bean; }}


/ 再坚持一下,让我把实例化过程先讲完! /

现在的逻辑已经走完了实例化前的 postProcessBeforeInstantiation 方法,那么现在我们的 bean 要进行实例化了,

  protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)      throws BeanCreationException {
// 实例化bean // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { // 有可能在本Bean创建之前,就有其他Bean把当前Bean给创建出来了(比如依赖注入过程中) instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 创建Bean实例 instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; }
// 后置处理合并后的BeanDefinition // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } }
// 为了解决循环依赖提前缓存单例创建工厂 // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 循环依赖-添加到三级缓存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
// Initialize the bean instance. Object exposedObject = bean; try { // 属性填充 populateBean(beanName, mbd, instanceWrapper); ...... return exposedObject; }

跟这篇无关的内容能删除的都删除了,主要有这几步我们需要注意下:

  1. createBeanInstance:创建实例,前提是之前没有创建过

  2. applyMergedBeanDefinitionPostProcessors:找到注入点,比如 AutowiredAnnotationBeanPostProcessor(@Autowired、@Value、@Inject)和 CommonAnnotationBeanPostProcessor(@Resource),这在实例化前和实例化后方法中间夹了一个处理合并 bean 定义的逻辑,注意一下

  3. addSingletonFactory:添加缓存,用来解决循环依赖,以后单独讲解

  4. populateBean:这一方法主要是属性填充也就是依赖注入的,但是官方把实例化后的 PostProcessors 方法写到这里了,所以也得贴出来,但是我们只看实例化相关的。

3


   

createBeanInstance

  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()); }
// BeanDefinition中添加了Supplier,则调用Supplier来得到对象 Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); }
// @Bean对应的BeanDefinition if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } ...... return instantiateBean(beanName, mbd); }


  1. resolveBeanClass:之前讲解过了,不重复讲了,就是拿到 class

  2. obtainFromSupplier:通过 Supplier 函数获取 bean,前提是你得声明 bean 定义

  3. instantiateUsingFactoryMethod:这种是使用@Bean 方法实例化对象,

  4. 后面省略了推断构造方法进行实例化对象,以后单独讲解推断构造方法

3.1


   

obtainFromSupplier

这一步其实我们用到的很少,主要是考虑到 Spring 自动注入的开销,我们自己可以就行实例化而已,比如我们这样写照样可以获取 bean,但是不会由 Spring 帮我们注入,得靠自己了:

//  创建一个Spring容器  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);  AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();  beanDefinition.setBeanClass(UserService.class);  beanDefinition.setInstanceSupplier(() -> new UserService());  applicationContext.registerBeanDefinition("userService", beanDefinition);  UserService userService = (UserService) applicationContext.getBean(UserService.class);  userService.test();


其实用法和@bean 注解相似,除了减少 Spring 自动注入的开销,实在没想到有啥用

3.2


   

instantiateUsingFactoryMethod

该方法内部逻辑很多,为了更加直观的展现,只贴出关键代码:

  @Override  public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,      @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(factoryMethod); return null; }); } else { ReflectionUtils.makeAccessible(factoryMethod); }
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get(); try { currentlyInvokedFactoryMethod.set(factoryMethod); // factoryBean就是AppConfig的代理对象(如果加了@Configuration) // factoryMethod就是@Bean修饰的方法 Object result = factoryMethod.invoke(factoryBean, args); if (result == null) { result = new NullBean(); } return result; } finally { if (priorInvokedFactoryMethod != null) { currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod); } else { currentlyInvokedFactoryMethod.remove(); } } } ...... }

比如我们定义的配置类中有很多@Bean 形式的方法,最终 Spring 会直接 invoke 调用被@Bean 修饰的方法从而实现实例化对象。

4


   

applyMergedBeanDefinitionPostProcessors

这里关于 MergedBeanDefinitionPostProcessors 的实现类不全讲解了,主要讲解下工作常用的注解 AutowiredAnnotationBeanPostProcessor,他是用来解析@Autowired、@Value、@Inject,看下他的默认源码:

public AutowiredAnnotationBeanPostProcessor() {    this.autowiredAnnotationTypes.add(Autowired.class);    this.autowiredAnnotationTypes.add(Value.class);    try {      this.autowiredAnnotationTypes.add((Class<? extends Annotation>)          ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));    }  }

看下他主要做了那些工作,关键代码附上:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {  // 如果一个Bean的类型是String...,那么则根本不需要进行依赖注入  if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {    return InjectionMetadata.EMPTY;  }
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz;
do { final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 遍历targetClass中的所有Field ReflectionUtils.doWithLocalFields(targetClass, field -> { // field上是否存在@Autowired、@Value、@Inject中的其中一个 MergedAnnotation<?> ann = findAutowiredAnnotation(field); if (ann != null) { // static filed不是注入点,不会进行自动注入 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; }
// 构造注入点 boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } });
// 遍历targetClass中的所有Method ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } // method上是否存在@Autowired、@Value、@Inject中的其中一个 MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { // static method不是注入点,不会进行自动注入 if (Modifier.isStatic(method.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static methods: " + method); } return; } // set方法最好有入参 if (method.getParameterCount() == 0) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } });
elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);}


  1. 如果一个 Bean 的类型是 String,那么则根本不需要进行依赖注入

  2. 遍历 targetClass 中的所有 Field,是否存在@Autowired、@Value、@Inject 中的其中一个,如果是 static 字段则不注入否则记录构造注入点

  3. 遍历 targetClass 中的所有 Method,是否存在@Autowired、@Value、@Inject 中的其中一个,如果是 static 字段则不注入否则记录构造注入点

5


   

populateBean

这个方法主要是属性填充,也就是所说的依赖注入的过程,我们不讲解这一部分,只讲解关于实例化最后的阶段 postProcessAfterInstantiation 方法,方法进来第一步就是调用 postProcessAfterInstantiation 方法。但是只看 Spring 源码的话,其实并没有太多实现,都是默认实现方法:

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {        if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {          return;        }      }    }


/ 总结 /

在本文中,我们深入探讨了 Spring 框架中 Bean 的实例化过程,关于某些细节以后我会单独拿出一篇文章单独讲解,我们来总结下实例化都做了哪些事情:

  1. 先从 bean 定义中加载当前类,因为最初 Spring 使用 ASM 技术解析元数据时只获取了当前类的名称

  2. 寻找所有 InstantiationAwareBeanPostProcessors 实现类,并调用实例化前的方法 postProcessBeforeInstantiation

  3. 进行实例化,这里会使用构造方法进行实例化

  4. 调用 applyMergedBeanDefinitionPostProcessors 找到所有 MergedBeanDefinitionPostProcessors 的实现类,比如我们的注入点(@Autowired 等)

  5. 寻找所有 InstantiationAwareBeanPostProcessors 实现类,并调用实例化后的方法 postProcessAfterInstantiation

通过本文的学习,读者将能够更深入地了解 Spring 框架中 Bean 的实例化过程,为后续的学习和实践打下坚实的基础。下一篇文章,我们将深入探讨 Bean 的初始化过程。


本篇文章来源于微信公众号: JAVA 开发微指南



微信扫描下方的二维码阅读本文

此作者没有提供个人介绍
最后更新于 2023-05-28