热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Spring核心源码深度解析(三)初始源码

Spring 源码测试实例 一个注解配置类,在com包里有一个User接口,两个实现了User接口的方法(提示:从本章开始,建议读者边看边实操) image 测试类,笔者将以Annot

Spring 源码测试实例

一个注解配置类,在com包里有一个User接口,两个实现了User接口的方法(提示:从本章开始,建议读者边看边实操)

Spring核心源码深度解析(三) 初始源码
image

测试类,笔者将以AnnotationConfigApplicationContext
这个注解类作为入口对源码进行深度分析

Spring核心源码深度解析(三) 初始源码
image

Spring 源码分析

进入笔者将以AnnotationConfigApplicationContext的构造方法

Spring核心源码深度解析(三) 初始源码
image

注意细节AnnotationConfigApplicationContext继承了GenericApplicationContext

Spring核心源码深度解析(三) 初始源码
image

所以会优先执行GenericApplicationContext的默认构造器,并且会创造一个叫DefaultListableBeanFactory的这么个类,

Spring核心源码深度解析(三) 初始源码
image

这个类分量很大,是Spring的核心类,我们点开DefaultListableBeanFactory这个类,

Spring核心源码深度解析(三) 初始源码
image

我们一步一步向上跟踪会发现它实现了BeanFactory,所以这就我们一直说的Bean工厂、Bean工厂,实际上Bean工厂也就是在这个时候就创建了,当然这个类还要其他重要的功能,笔者暂时放一放,咱们继续往下走,执行完父类的构造器后,现在开始执行自己的构造器了

public AnnotationConfigApplicationContext() {   
    //这个reader顾名思义是一个读取器,而且十分重要,稍后会说明为什么重要  
    this.reader = new AnnotatedBeanDefinitionReader(this);  
    //这个scanner说实话没有什么卵用,因为在spring内部自己new了一个扫描器,而不是用的这个对象,而这个类是交给程序员手动获取的,基本用不到  
    this.scanner = new ClassPathBeanDefinitionScanner(this);
    }   

如上图所示:AnnotationConfigApplicationContext构造器创建了一个读取器,一个扫描器,而这个scanner为什么由上述注释所写的后期我们在扫描的时候证明。进入this.reader=new AnnotatedBeanDefinitionReader(this); 这行代码调入

Spring核心源码深度解析(三) 初始源码
image

然后构造器相互调用最终调用这个构造器

Spring核心源码深度解析(三) 初始源码
image

进入AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
里面又是委托模式,继续渗入registerAnnotationConfigProcessors(registry, null);
最终进入核心方法registerAnnotationConfigProcessors()这个方法大概就做了两件事情,获取之前创建的DefaultListableBeanFactory,然后往里面装一些工具组件,包含排序组件、转换器组件、以及4个特别特别重要的后置处理器。分别是


1、ConfigurationClassPostProcessor
2、AutowiredAnnotationBeanPostProcessor
3、CommonAnnotationBeanPostProcessor
4、EventListenerMethodProcessor

在registerAnnotationConfigProcessors()涉及到Spring后置处理器和BeanDefinition,下面会进行简要分析

Spring后置处理器

什么是后置处理器,笔者这里对Spring其中一个顶层的后置处理器进行详细说明

Spring核心源码深度解析(三) 初始源码
image

看了上面的注释,读者可能还是比较懵逼,我们在实践一下

Spring核心源码深度解析(三) 初始源码
image

我们实现了BeanFactoryPostProcessor拿到了ConfigurableListableBeanFactory,然后我们从工厂可以获取某一个类的BeanDefinition(注意:很多小伙伴一个有一个误区,不知道什么是对象什么是Bean,笔者认为Bean一定是对象,对象不一定是Bean,而对象成为Bean的条件就是完成Spring的整体生命周期),拿到从工厂获取的BeanDefinition,是不是就可以进行修改这个BeanDefinition,再结合笔者上文后置处理器的注释,相信这个时候读者应该对后置处理器有一定初步的认识,当然这个时候小伙伴们可能就要问了,我拿到BeanDefinition有什么用?看下图,

Spring核心源码深度解析(三) 初始源码
image

这里并没有对Spring Bean流程详细介绍,只是对整体流程描述了大概。如果还是不明白我们在后面会详细说明后置处理器的作用。

BeanDefinition

在think in java的作者提出,一切皆为对象,一切皆可抽象,而BeanDefinition正是Spring抽象设计的精髓,回到上文笔者强调Bean和对象不是同一个概念,Spring认为仅仅是java自带的对象是不能满足于我所需求的,就好比单例、Lazy等一些特性无法满足,所以Spring定义一个BeanDefinition作为对象的抽象,来实现对象的抽象,(当然BeanDefinition的分量很高,笔者在后面会更详细的介绍它具体的作用)明白这点后我们回到代码:

public static Set registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {

    //从注册器获取beanFactory
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      //这里是判断beanFactory有没有排序的工具
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      //这里是判断beanFactory有没有转换器
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }
    //之后你会看到很多BeanDefinitionHolder,这个BeanDefinitionHolder其实没什么作用,就是一个
    //封装了BeanDefinition的map,而BeanDefinition是对spring将要实例化对象的一个缓存,
    //类似于对象的class,只是功能比class更丰富
    Set beanDefs = new LinkedHashSet(8);
    //重点来了,这里涉及到了一个概念叫BeanFactoryPostProcessor,详细看接口
    //registerPostProcessor这个方法就是将RootBeanDefinition放到工厂的map对象去
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    //下面是注册五个类,但有一个类会被忽略,所以总共只注册了五个类
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      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)) {
      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)) {
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
  }

这里其实就是获取前面创建的工厂,然后向工厂装一些组件,目的就是初始化工厂,然后再为工厂创建Spring自定义的后置处理器作为BeanDefinition存起来,然后返回,这是我们的this已经执行完毕,回到这个图。

Spring核心源码深度解析(三) 初始源码
image

咱们再看一遍注释,相信读者大致能理解
我们再看register方法->this.reader.register(componentClasses);->registerBean(componentClass);->doRegisterBean(beanClass, null, null, null);

  void doRegisterBean(Class beanClass, @Nullable Supplier instanceSupplier, @Nullable String name,
      @Nullable Class extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    //这里可以看到使用AnnotatedGenericBeanDefinition去创建的 后面会通过这个类的父接口去做一些判断
    //此外在这个创建注解BD的时候就对内部的元注解进行初始化,自己有标识了注解
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
    }
    abd.setInstanceSupplier(instanceSupplier);
    //获取作用域元数据
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    //这里是对Config配置类进行注解信息的设置,Lazy,Primary,DependsOn等等
    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);
    //将bd注册到我们的BeanFactory去
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }

其实我们可以看到核心代码就是最下面一句, BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);将我们的配置类或普通类注册到BeanDefinitionMap集合里。而前面只是做一些判断,比如是不是Lazy,Primary,DependsOn,有没有Supplier等

深度分析Spring核心方法refresh()

refresh()目录
//这个方法没什么用,里面都是一些系统环境设置
prepareRefresh();
// 这里只是将beanFactory拿出来
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 对beanFactory添加一些处理器,并设置一些属性
prepareBeanFactory(beanFactory);
// 空方法
postProcessBeanFactory(beanFactory);
// 这里是执行实现了BeanFactoryPostProcessor这个接口的子类
// 重点就是spring自己的一个类
// 秒扫出要实例化的类,放进工厂的beanDef里面,这里只是放的bd并不是真正的实例化对象invokeBeanFactoryPostProcessors(beanFactory);
//注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this 
context.initMessageSource();
// 创建ApplicationEventMulticaster这么一个类initApplicationEventMulticaster();
//空方法  
onRefresh();
// 注册监听器
registerListeners();
//完成对bean的创建finishBeanFactoryInitialization(beanFactory);
// publish corresponding event.
finishRefresh();

我们可以看到Spring在refresh方法里面做了很多很多的事情,我们逐步分析:

prepareRefresh():这个方法并不用太关注,这是Spring记录一些系统日期、日志之类的,我们直接跳过。

obtainFreshBeanFactory():这个方法只是将创建的工厂拿出来给后续的方法作为参数利用

Spring核心源码深度解析(三) 初始源码
image

prepareBeanFactory():


protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 这里是对beanFactory设置一些工具类,后面用到再说,先跳过
    beanFactory.setBeanClassLoader(getClassLoader());
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 添加一个ApplicationContextAwareProcessor后置处理器
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //设置一些需要忽略的类,避免重复,这里就是避免从面部传进这些class影响Spring内部操作
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

看这句代码,beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));、进入ApplicationContextAwareProcessor 找到下面代码

Spring核心源码深度解析(三) 初始源码
image

可以看到里面有大量的回调接口。如果没搞明白我们写了例子

Spring核心源码深度解析(三) 初始源码
image
Spring核心源码深度解析(三) 初始源码
image

可以看出,我们可以通过回调拿到Spring内部的对象,这里可以结合再一个实例,单例对象的属性注入原型对象,就需要这种方式解决,而这个对象那里来的呢,咱们回到源码:

  //解决依赖注入来源问题
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 注册一个用来销毁Bean的后置处理器
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
  }

这里就是Spring内部注册的对象,这里涉及到一个数据源的问题,我们会在依赖注入的环节单独详细说明笔者暂且可以认为这些对象没有经过Spring的生命周期,但可以提供依赖注入。

postProcessBeanFactory()

Spring核心源码深度解析(三) 初始源码
image

空壳方法,这里猜测是Spring为自己预留的拓展功能。接下来的方法较为重要,笔者打算单独开一章节详细分析

本小节总结:
1、创建一个工厂 this.beanFactory = new DefaultListableBeanFactory();
2、创建一个读取器 this.reader = new AnnotatedBeanDefinitionReader(this);
3、对beanFactory添加一些组件工具,添加4个后置处理器
4、通过之前创建的读取器把传进来的类转换为BeanDefinition注册到工厂里。

5、Spring在自己内部设置了一些数据源信息比如ApplicationContext、Resourse等

6、添加了一个ApplicationContextAwareProcessor后置处理器提供Aware回调

7、忽略一些Spring内部关键的类,防止外部修改或影响了Spring内部的核心类


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
author-avatar
手机用户2502859545
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有