Análisis del código fuente del ciclo de vida de Spring's Bean (1)

Análisis del código fuente del ciclo de vida de Spring's Bean (1)

  • Proceso del ciclo de vida del frijol
  • El paquete Bean escanea el proceso subyacente
  • Lector de metadatos
  • Merge Bean Definición
  • clase de carga

¿Cuál es el ciclo de vida del frijol?

El ciclo de vida de un frijol se refiere a cómo se genera y destruye un frijol en primavera.

Diagrama de flujo del ciclo de vida del frijol

Ciclo de vida del frijol.png

Ciclo de vida del frijol:

  1. Iniciar contexto de aplicación
  2. Crear BeanFactory
  3. Inicializar BeanFactory
  4. Procesamiento posterior en BeanFactory: el escaneo de paquetes se realizará aquí para encontrar todos los archivos de clase calificados
  5. BeanDefition generado
  6. Merge Bean Definición
  7. clase de carga
  8. Antes de la creación de instancias
  9. instanciar
  10. construcciones inferidas
  11. instanciar
  12. Postprocesamiento de BeanDefinition
  13. después de la instanciación
  14. atributo de relleno
  15. Después de llenar las propiedades
  16. Ejecute la interfaz de devolución de llamada de Aware
  17. Antes de la inicialización
  18. inicialización
  19. después de la inicialización

Diagrama de flujo subyacente de escaneo de paquetes de frijoles

Cuando comience el período de primavera, se realizará el escaneo de paquetes y se llamará primero a ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage).

Para escanear una ruta de paquete y analizar el archivo de clase requerido en un BeanDefinition y colocarlo en una colección establecida.

El paquete Spring escanea el proceso subyacente.png

El paquete Spring escanea el proceso subyacente :

  1. Primero, obtenga todos los archivos .class bajo la ruta del paquete especificado a través de ResourcePatternResolver (en el código fuente de Spring, este archivo se empaquetará como un objeto de recurso)
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// Class文件的File对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
复制代码
  1. Iterar sobre cada objeto de recurso
for (Resource resource : resources) {
    ...
}
复制代码
  1. Use MetadataReaderFactory para analizar el objeto Resource para obtener MetadataReader (en el código fuente de Spring, la clase de implementación específica de MetadataReaderFactory es CachingMetadataReaderFactory y la clase de implementación específica de MetadataReader es SimpleMetadataReader)
// 从class文件中获取类元数据信息,比如注解信息,接口信息等,底层采用了ASM技术,这里就相当于这个类的代表
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
复制代码
  1. 利用MetadataReader进行excludFilters和includeFilters,以及条件注解@Conditional的筛选(对于@Conditional条件注解,并不是理解为某个类上加了这个注解就匹配了而是如果存在了就会调用注解所指定类的match方法进行匹配,匹配成功就通过筛选了,否则就会排除掉),对于加了@Component注解的类,默认是被包含在includeFilters中的,除非自行加了excludeFilter条件去进行排除在外

    protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
        // 如果被排除过滤器匹配了就不是Bean
        for (TypeFilter tf : this.excludeFilters) {
          if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return false;
          }
        }
    ​
        // Spring里面默认就会添加一个includeFilter
        // 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
        for (TypeFilter tf : this.includeFilters) {
          if (tf.match(metadataReader, getMetadataReaderFactory())) {
            return isConditionMatch(metadataReader);
          }
        }
        return false;
    }
    复制代码
  1. 筛选通过之后,基于MetadataReader生成ScannedGenericBeanDefinition

      ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    复制代码
  1. 基于MetadataReader判断是对应的类是不是接口或抽象类

    • 如果不是一个独立的类比如说是一个普通的内部类,就不能成为一个Bean,

    • 如果是顶级类或者静态内部类就是独立的

    • 如果是接口或者抽象类,也不能成为一个Bean

    • 如果是抽象类但是包含了@LookUp就是一个独立的类

      protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return (metadata.isIndependent() && (metadata.isConcrete() ||
        (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
      }
      复制代码
  1. 如果筛选通过,那么就表示扫描到了一个Bean,将ScannedGenericBeanDefinition加入到Set集合中

    if (isCandidateComponent(sbd)) {
    if (debugEnabled) {
    logger.debug("Identified candidate component class: " + resource);
    }
    candidates.add(sbd);
    }
    复制代码

MetadataReader

imagen.png

MetadataReader表示类的元数据读取器,主要包含一个AnnotationMetadata,功能有:

  • 获取类的名字
  • 获取父类的名字
  • 获取所实现的所有接口
  • 获取所有内部类的名字
  • 判断是不是抽象类
  • 判断是不是一个接口
  • 判断拥有某个注解的方法集合
  • 获取类上添加的所有注解信息
  • 获取类上的所有注解类型集合

注意: CachingMetadataReaderFactory解析某个.class文件得到MetadataReader对象是利用了ASM,并没有加载这个类到JVM内存中去,并且最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储的是当前类的名字,而不是class对象.(beanClass属性的类型是Object,它既可以存储类的名字,也可以存储class对象)

除了可以通过扫描得到BeanDefinition对象,我们还可以直接通过bean标签的形式去定义或者@Bean注解

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
    implements BeanDefinition, Cloneable {
  ...
/**
   * 为什么这里是Object,而不是Class<?>
   *     因为这里还没有加载,只是通过ASM技术去解析了这个类,并没有去解析,只是把这个类的名字设置给了BeanDefinition的属性,当创建这个Bean的时候,才会去真正加载
   */
  @Nullable
  private volatile Object beanClass;
  
  } 
复制代码

合并BeanDefinition

通过扫描得到的所有BeanDefinition之后,就可以根据BeanDefinition创建Bean对象了,但是在Spring中支持父子BeanDefintion,和Java父子类类似,但是不是一回事.

如如下情况,child无疑是单例bean

  <bean id="parent" class="linc.cool.service.Parent" scope="prototype"/>
  <bean id="child" class="linc.cool.service.Child" />
复制代码

但是如下情况,child继承了parent的属性,成为了原型bean

  <bean id="parent" class="linc.cool.service.Parent" scope="prototype"/>
  <bean id="child" class="linc.cool.service.Child" parent="parent" />
复制代码

而在根据child来生成Bean对象之前,需要进行BeanDefinition的合并,得到完整的child的BeanDefinition

(Spring源码中合并后的BeanDefinition是RootBeanDefinition,对应的合并逻辑在AbstractBeanFactory#getMergedBeanDefinition)

加载类

BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化对象就必须先去加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory#createBean方法中一开始会调用resolveBeanClass(mbd, beanName) 去进行判断

如果beanClass属性的类型是Class,那么就直接返回,否则,就会根据类名进行加载

后续就是通过AbstractBeanFactory#doResolveBeanClass去进行加载了,其中会利用BeanFactory所设置的类加载器来加载类

Si no se establece, el cargador de clases devuelto por AbstractBeanFactory#ClassUtils.getDefaultClassLoader() se usa para cargar la clase de forma predeterminada

// 如果beanClass被加载了,就直接返回,加载了的话存的是Class
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);
}
复制代码
public boolean hasBeanClass() {
  return (this.beanClass instanceof Class);
}
复制代码
  public ClassLoader getBeanClassLoader() {
    return this.beanClassLoader;
  }
复制代码
  private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
复制代码

ClassUtils.getDefaultClassLoader()

  1. La prioridad vuelve al ClassLoader en el hilo actual
  2. Si la clase que se carga en el subproceso es nula, devuelva el cargador de clases de la clase ClassUtils
  3. Si el cargador de clases de ClassUtils está vacío, significa que es la clase ClassUtils cargada por el cargador de clases de BootStrap, luego volverá al cargador de clases del sistema durante mucho tiempo.
@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.
    // 默认使用AppClassLoader
    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;
}
复制代码

Supongo que te gusta

Origin juejin.im/post/7086068570974601229
Recomendado
Clasificación