深入理解 Spring 环境初始化

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 终于,有一天我也来看Spring的源码了,看了一阵之后感觉心情那叫一个舒畅,对Spring底层的实现也有了进一步的了解, 最直观的感受就是Spring的命名风格很赞,很长,真的长到使人见名知意, 闲言少叙,开始整理笔记了

终于,有一天我也来看Spring的源码了,看了一阵之后感觉心情那叫一个舒畅,对Spring底层的实现也有了进一步的了解, 最直观的感受就是Spring的命名风格很赞,很长,真的长到使人见名知意, 闲言少叙,开始整理笔记了


程序的入口#


AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);


跟进这个AnnotationConfigApplicationContext()程序的启动入口, 注解配置的应用上下文.主要做了下面的三件事

  • 调用本类无参构造方法
  • 调用register(annotatedClasses) 将我们传递进来的配置类注册进BeanFactoryBeanDefinitionMap
  • 刷新容器


public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    register(annotatedClasses);
    refresh();
  }


创建BeanFactory#



首先调用本类的无参构造方法,,通过上图,可以看到,AnnotationConfigAllicationContext的父类是GenericApplicationContext但是,在执行本类的无参构造方法时会先执行父类的无参构造方法.它父类的无参构造方法我贴在下面,就做了一件事,初始化了Spring的BeanFactory,没错就是Spring的Bean工厂,由于两者的继承关系,我们就任务,AnnotationConfigApplicationContext的Bean工厂被初始化了


public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
  }


创建AnnotatedBeanDefinitionReader加载#


接着回到这个构造方法的源码我贴在下面, 这个构造方法主要做了两件事

  • 为应用的上下文创建reader读取器, 读取被添加了注解的类信息
  • 实例化了一个Scanner, 这个Scanner可以用去做包扫描的工作,但是Spring根据我们的配置信息去进行包扫描的工作时,并没有使用这个扫描器,而是自己new 了一个,当前的扫描器可以理解成是方便程序员使用而创建的


public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this); 
    this.scanner = new ClassPathBeanDefinitionScanner(this);
  }


下面跟进AnnotatedBeanDefinitionReader扫描器的创建过程,经过几个没有重要逻辑的方法,我们会进入

registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source),下面是源码: 这算是Spring初始化的一个小高潮了!!!,为啥这样说呢? 因下面的逻辑中,为Spring初始化过程中,构建BeanFactory提供了几个开天辟地性质的RootBeanDefinition``


  • 首先是在为BeanFactory添加了两个大组件
  • AnnotationAwareOrderComparator用于解析@Order@Priorty注解
  • ContextAnnotationAutowireCandidateResolver 提供了懒加载的支持
  • 然后就是往BeanFactory中的BeanDefinitionMap中添加了6个RootBeanDefinition
  • ConfigurationClassPostProcessor
  • AutowiredAnnotationBeanPostProcessor
  • ...


public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    BeanDefinitionRegistry registry, @Nullable Object source) {
  //   得到bean工厂
  DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  if (beanFactory != null) {
    if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
      //  给Bean工厂添加原材料
      //  AnnotationAwareOrderComparator 主要能解析@Order注解和@Priority
      beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    }
    if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
      //  ContextAnnotationAutowireCandidateResolver 提供处理懒加载(Lazy)相关的功能
      beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    }
  }
  //   作用是方便传递参数BeanDefinitionHolder
  Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
  // BeanDefinition的注册,这里很重要,需要理解注册每个bean的类型
  //   就是判断工厂中有没有包含 CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 名称的bean, Spring在启动时,工厂肯定是空的返回false , 加上! 表示ture
  if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {//configuration_annotation_processor_bean_name
    //   注意: 下面的ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,间接实现了 BeanFactoryPostProcessor bean工厂的后置处理器
    //   RootBeanDefinition可以理解成 描述Spring内部类的Definition
    //   除了通过AnnotationedBeanDefinitionReader把 加上了注解的类加载成bean,下面的第二种方式, 通过new RootBeanDefinition, 进而将 XXX.class起来注册进bean工厂
    //   这是使用第二种方式, 通过new Spring自己实现的BeanDefinition接口的类,将java转换成 Bean 然后put进BeanFactory的BeanDefinitionMap中
    //   下面的111-666 就是最先放置进去的6个Spring的RootBean对象
    //   ---111---------------------------
    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    def.setSource(source);
    //   跟进去 registerPostProcessor
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
  }
  if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //AutowiredAnnotationBeanPostProcessor 实现了 MergedBeanDefinitionPostProcessor
    //MergedBeanDefinitionPostProcessor 最终实现了 BeanPostProcessor
    //   ---222---------------------------
    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  }
  if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //   ---333---------------------------
    RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  }
  // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
  if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    //   ---444---------------------------
    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
  }
  // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
  if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition();
    try {
      def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
          AnnotationConfigUtils.class.getClassLoader()));
    }
    catch (ClassNotFoundException ex) {
      throw new IllegalStateException(
          "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
    }
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
  }
  if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    //   ---555---------------------------
    RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  }
  if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
    //   ---666---------------------------
    RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  }
  return beanDefs;
}


上面的代码中有来如下两个亮点:


亮点1:RootBeanDefinition#


首先涉及到的知识点就是,Spring有哪几种方式将对象转成BeanDefinition? 其实是有两种,第一种就是让Spring通过Scanner去扫描包解析程序员提供的添加了注解的类,这是个自动完成的过程,第二种就是Spring通过new RootBeanDefinition等诸多的BeanDefinition接口的实现类, 然后将Spring原生的对象当成参数传递进去进而转换成BeanDefinition, 当然,Spring在这里选择的就是第二种方法


亮点2:ConfigurationClassPostProcessor#


这个类很牛,为什么这么说呢? 先看一下他的继承类图



没错,他是6个RootBeanDefinition中唯一的一个实现BeanFactoryPostProcessor的,其他的五个RootBeanDifinition实现的都是BeanPostProcessor, 其实也不用懵逼,只要我们整明白这里说的BeanPostProcessorBeanFactoryPostProcessor的作用就好了,然后在这里我用下面的两个模块解释


BeanPostProcessor#


接口的抽象方法源码如下:


public interface BeanPostProcessor {
@Nullable
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
@Nullable
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }
}


两个方法名,见名知意: 第一个会在 对象的 constructor 之后,init()方法之前调用

第二个会在init()方法之后调用


但是,大家可以发现,它的调用时机都是在构造方法执行之后进行拦截,这时候BeanDefinition已经被实例化了


BeanFactoryPostProcessor#


@FunctionalInterface
public interface BeanFactoryPostProcessor {
  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}


它就比较厉害了, 这也是Spring牛的地方,它不仅仅会替我们维护这些Bean,而且还通过当前的BeanFactoryPostProcessor,为程序员开放一个缺口,让程序员可以参与到Bean的创建过程中来,为什么这样说呢, 其实大家可以看到,它唯一的抽象方法中的入参位置上是谁? 没错,就是BeanFactory, Bean工厂都给我们了,那不是想干啥干啥?

其次,它的作用时机是执行Bean的构造方法之前


最直接的应用场景: 当一个单例的Bean依赖 多例的Bean时,我们多次通过 应用的上下文获取出来的单例bean的hashcode都是唯一的这没错,但是紧接着打印它依赖的多例对象的hashcode同样是相同的,这种单例失效的问题,就可以根据这个知识点从容解决

前面说的ConfigurationClassPostProcessor就是BeanFactoryPostProcessor的实现类,并且它也不辱使命, 完美的使用作用时机不同的特点,在程序员提供的配置类的构造方法调用之前,就先入为主,围棋生成了 cglib代理对象


接着看代码,回到上面的代码,我们看如何将RootBeanDefinition注册进BeanFactory, 我从上面截取一行代码放在这里


//   跟进去 registerPostProcessor
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));


跟进这个registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)


private static BeanDefinitionHolder registerPostProcessor(
    BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {
  definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  //   registerBeanDefinition()
  registry.registerBeanDefinition(beanName, definition);
  return new BeanDefinitionHolder(definition, beanName);
}


我们关注这个registry.registerBeanDefinition(beanName, definition); , 可以看到,其实这个registerBeanDefinition()BeanDefinitionRegistry的抽象方法,我们要找的是它的实现类,那问题来了, 是谁实现他呢? 可以回到博客顶部,看看第一个图,没错Spring的BeanFactory,也就是DefualtListableBeanFactory实现了这个接口,虽然有点意外,一个工厂竟然还是一个注册器,但是这也是事实情况, 看看这个工厂是如何做的吧 .原函数很长,我截取了部分源码如下: 它的解释我写在源码的下面


public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {
            ...
      else {
        //   添加进入容器中, 最终的结果就是,这个map中存在哪些类,Spring的IOC中就有哪些类
        // Still in startup registration phase
        this.beanDefinitionMap.put(beanName, beanDefinition);
        //   单独使用一个list存放名字
        this.beanDefinitionNames.add(beanName);
        this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
    }
    if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
    }


可以看到,他将一开始的6个RootBeanDefinition全都都put进了一个map中, 下面这个map


private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);


key就是beanName, value就是BeanDefinition

这也是迄今为止我们遇到的第一个map, 这个map是BeanFactory的一个组件,但是它可不是传说中的IOC容器,大家也看到了它里面存放的是BeanDefinition,而不是Bean


将配置类注册进BeanFactory#


回到一开始AnnotationConfigApplicationContextregister(annotatedClasses);方法,然后一路往下跟,会经过几个没有什么重要逻辑的方法, 然后来到这里


public void register(Class<?>... annotatedClasses) {
  for (Class<?> annotatedClass : annotatedClasses) {
    //  继续跟进去
    registerBean(annotatedClass);
  }
}


通过上面的代码,我们可以回想,annotatedClasses这个可变长度的参数,其实就是我们在AnnotationConfigApplicationContext中传递进来的主配置类MainConfig, 也就是说,这个主配置类是可以存在多个的


接着往下跟


<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
        // 可以将当前类理解成一个方便参数传递的封装类
        // 意为: 被加上注解的通用的BD
        // 将传递进来的 主配置类封装进 这个AnnotatedGenericBeanDefinition
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
    }
    abd.setInstanceSupplier(instanceSupplier);
        // 解析出它的元数据
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        // 设置它的作用域
    abd.setScope(scopeMetadata.getScopeName());
        // 名称生成器, 目的是为BeanDefinition取个名字,因为这个BD最终被存放到一个map中,
        // 默认情况下@Configuration(value = "XXX") 这个value有值,就是使用这个当成名字
        // 都这就使用 类名首字母小写当成名字
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
        // 处理bean上的通用注解, @Lazy  @Dependon @Primary role等
    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));
        }
      }
    }
    for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
      customizer.customize(abd);
    }
        // 理解成方便参数传递的封装类
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd,beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
        // 我们关注的重点, 注册BeanDefinition
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }


上面的函数的主要作用如下: 将我们通过AnnotationConfigApplicationContext构造函数传递进来的主配置类封装进了AnnotatedGenericBeanDefinition中,然后解析它身上的其他注解完成属性的赋值


接着跟进registerBeanDefinition()方法


public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {
    //   再来这个方法之前封装了一个 difinitionHolder , 然后在这里又把它拆分开传递给了下面的函数
    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    //   在当前的BeanDefinitionReaderUtils中使用
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
      for (String alias : aliases) {
        registry.registerAlias(beanName, alias);
      }
    }
  }


继续跟进


registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());


于是有回到了上面注册6大RootBeanDefinition的逻辑中,将我们的主配置类注册进BeanFactoryBeanDefinitionMap


未完待续...

相关文章
|
5月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
展望未来,随着5G、边缘计算等新技术的兴起,微服务架构的设计理念将会更加深入人心,Spring Cloud和Netflix OSS也将继续引领技术潮流,为企业带来更为高效、灵活且强大的解决方案。无论是对于初创公司还是大型企业而言,掌握这些前沿技术都将是在激烈市场竞争中脱颖而出的关键所在。
93 0
|
6月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
129 0
|
3月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
134 4
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
3月前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
79 2
|
4月前
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
73 1
|
7月前
|
安全 Java Spring
Spring问题之如何配置Bean的初始化方法和销毁方法
Spring问题之如何配置Bean的初始化方法和销毁方法
|
7月前
|
存储 缓存 安全
Spring初始化加速的思路和方案问题之手动指定要异步初始化的bean中的问题如何解决
Spring初始化加速的思路和方案问题之手动指定要异步初始化的bean中的问题如何解决
|
7月前
|
Java Spring
Spring初始化加速的思路和方案问题之在BeanFactory#doGetBean方法中,栈状态的变化影响bean的初始化的问题如何解决
Spring初始化加速的思路和方案问题之在BeanFactory#doGetBean方法中,栈状态的变化影响bean的初始化的问题如何解决
|
7月前
|
存储 Java Spring
Spring初始化加速的思路和方案问题之替换默认的Spring Bean初始化逻辑中的问题如何解决
Spring初始化加速的思路和方案问题之替换默认的Spring Bean初始化逻辑中的问题如何解决