Spring의 Bean 라이프 사이클 소스 코드 분석 (1)

Spring의 Bean 라이프 사이클 소스 코드 분석 (1)

  • 빈 라이프 사이클 프로세스
  • Bean 패키지는 기본 프로세스를 스캔합니다.
  • 메타데이터리더
  • BeanDefinition 병합
  • 로드 클래스

Bean 라이프 사이클이란 무엇입니까?

Bean 의 라이프 사이클은 Spring에서 Bean이 생성되고 소멸되는 방식을 나타냅니다.

Bean 수명 주기 순서도

빈 라이프 사이클.png

콩 수명 주기:

  1. ApplicationContext 시작
  2. BeanFactory 생성
  3. BeanFactory 초기화
  4. BeanFactory의 후처리: 모든 정규화된 클래스 파일을 찾기 위해 여기에서 패키지 스캔이 수행됩니다.
  5. 생성BeanDefition
  6. BeanDefinition 병합
  7. 로드 클래스
  8. 인스턴스화 전
  9. 인스턴스화
  10. 추론된 구성
  11. 인스턴스화
  12. BeanDefinition의 후처리
  13. 인스턴스화 후
  14. 채우기 속성
  15. 속성을 채운 후
  16. Aware 콜백 인터페이스 실행
  17. 초기화 전
  18. 초기화
  19. 초기화 후

Bean 패키지 스캔 기본 순서도

Spring 기간이 시작되면 패키지 스캔이 수행되고 ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)가 먼저 호출됩니다.

패키지 경로를 스캔하고 필요한 클래스 파일을 BeanDefinition으로 구문 분석하고 집합 컬렉션에 넣습니다.

Spring 패키지는 기본 process.png를 스캔합니다.

Spring 패키지는 기본 프로세스를 스캔합니다 .

  1. 먼저 ResourcePatternResolver를 통해 지정된 패키지 경로 아래의 모든 .class 파일을 가져옵니다(Spring 소스 코드에서 이 파일은 Resouce 객체로 패키징됩니다).
// 获取basePackage下所有的文件资源
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
// Class文件的File对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
复制代码
  1. 각 Resource 객체에 대해 반복
for (Resource resource : resources) {
    ...
}
复制代码
  1. MetadataReaderFactory를 사용하여 Resource 객체를 구문 분석하여 MetadataReader를 가져옵니다(Spring 소스 코드에서 MetadataReaderFactory의 특정 구현 클래스는 CachingMetadataReaderFactory이고 MetadataReader의 특정 구현 클래스는 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

이미지.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所设置的类加载器来加载类

설정하지 않으면 AbstractBeanFactory#ClassUtils.getDefaultClassLoader() 에 의해 반환된 클래스 로더 가 기본적으로 클래스를 로드하는 데 사용됩니다.

// 如果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. 우선 순위는 현재 스레드의 ClassLoader로 반환됩니다.
  2. 스레드에서 로드하는 클래스가 null이면 ClassUtils 클래스의 클래스 로더를 반환합니다.
  3. ClassUtils의 클래스 로더가 비어 있으면 BootStrap 클래스 로더에 의해 로드된 ClassUtils 클래스임을 의미하며 오랜 시간 동안 시스템 클래스 로더로 돌아갑니다.
@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;
}
复制代码

추천

출처juejin.im/post/7086068570974601229