Spring源码系列:核心概念解析

这篇具有很好参考价值的文章主要介绍了Spring源码系列:核心概念解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本文旨在为读者解析Spring源码中的关键类,以便读者在深入阅读源码时,能够了解关键类的作用和用途。在阅读Spring源码时,经常会遇到一些不熟悉的概念,了解关键类的作用可以帮助读者更好地理解这些概念。

BeanDefinition

BeanDefinition是Spring框架中的一个重要概念,它定义了一个Bean的基本属性和行为,比如:

  1. BeanClassName,当前的bean名字
  2. Scope,是否单例,具体枚举:#SCOPE_SINGLETON、#SCOPE_PROTOTYPE
  3. LazyInit,是否懒加载,默认不是
  4. DependsOn,是否依赖其他bean,如果依赖,则会先创建依赖bean
  5. InitMethodName,初始化方法名称
  6. DestroyMethodName,销毁类方法名称
  7. ......还有更多,但是这几个大体已经差不多了

BeanDefinition的作用非常重要,它可以帮助Spring容器更好地管理Bean的生命周期和依赖关系。在Spring框架中,我们经常会通过注解方式来定义Bean:

  1. < bean/>
  2. @Bean
  3. @Component(@Controller、@Service)

这些都是被称为申明式定义Bean。就是使用Spring提供好的封装。

除了注解方式,我们还可以通过编程方式来定义Bean,这时就需要直接使用BeanDefinition来创建BeanDefinition对象,并设置对应的属性,然后将其注册到Spring容器中,比如

    // 创建一个Spring容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(UserService.class);
        //当然还可以设置其他上面我说的其他属性:懒加载什么的
        applicationContext.registerBeanDefinition("userService", beanDefinition);

        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.test();

无论是通过注解方式还是编程方式来定义Bean,最终都是需要使用BeanDefinition来描述Bean的基本属性和行为,然后将其放入Spring容器中进行管理。

BeanDefinitionReader

BeanDefinitionReader是Spring框架中的一个重要组件,主要用于读取和操作BeanDefinition对象。虽然我们在使用Spring框架时很少直接使用BeanDefinitionReader,但在Spring源码中却扮演着非常重要的角色,相当于Spring源码的基础设施。

BeanDefinitionReader的核心方法包括以下几个:

  1. BeanDefinitionRegistry,用来注册bean定义,相当于一个工厂
  2. BeanNameGenerator,用来生成bean名字的生成器
  3. loadBeanDefinitions,从资源中加载bean

XmlBeanDefinitionReader

XmlBeanDefinitionReader是BeanDefinitionReader的子类,可以用于从XML文件中读取BeanDefinition并注册到Spring容器中。使用XmlBeanDefinitionReader的步骤如下:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(context);
//加载xml中配置的所有<bean>
int i = xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(context.getBean("userService"))

AnnotatedBeanDefinitionReader

细心的朋友,应该可以发现AnnotatedBeanDefinitionReader是一个单独的类,不是BeanDefinitionReader的子类,但它的方法与BeanDefinitionReader基本相同,官方说是方便的适配器,用于编程注册bean类,他可以解析@Conditional,@Scope、@Lazy、@Primary、@DependsOn、@Role、@Description相关注解,具体操作如下:

// 创建一个Spring容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

//        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//        beanDefinition.setBeanClass(UserService.class);
//        applicationContext.registerBeanDefinition("userService", beanDefinition);

        new AnnotatedBeanDefinitionReader(applicationContext).registerBean(UserService.class);

        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.test();

同样的,他也可以让我们注册的bean走完创建的整个生命周期过程。

ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner也是一个用于注册BeanDefinition的工具类,与BeanDefinition接口没有直接关系。ClassPathBeanDefinitionScanner可以扫描指定包路径下带有特定注解的类,并将其解析成BeanDefinition,注册到Spring容器中。主要是他有个scan方法对我们定义的basepackage包路径进行解析扫描所有带有@component、@ManagedBean(JSR-250标准)、@Named(JSR-330标准)
使用ClassPathBeanDefinitionScanner的步骤如下:

// 创建一个Spring容器  
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);  
  
new ClassPathBeanDefinitionScanner(applicationContext).scan("com.xiaoyu");  
UserService userService = (UserService) applicationContext.getBean("userService");  
userService.test();

BeanFactory

BeanFactory是Spring框架中的一个重要接口,他就是Spring用于管理Bean对象的创建和管理,看他的几个主要方法就知道了:

  1. getBean,可以根据name、type等获取bean对象
  2. containsBean,是否bean工厂中有某个对象
  3. isSingleton,判断是否是单例
  4. isTypeMatch,判断改name是否匹配类型
  5. getType,根据bean名字获取类型
  6. getAliases。获取别名数组
    看着主要几个接口实现,基本都是围绕bean所做的,然后根据接口再看他的实现类就方便许多了,

DefaultListableBeanFactory

如果看过源码的朋友肯定对这个实现类不陌生,如果对这个实现类陌生的朋友,那请记住这个重要的实现类,它实现了很多接口、且继承了多层父类,所以他的功能也是相当之多。我们来看看他的主要方法:

  1. containsBeanDefinition,查看是否包含某个bean定义,因为该类维护了一个Map<String, BeanDefinition> beanDefinitionMap属性。
  2. determineAutowireCandidate,决定注入哪个bean,@Primary-->优先级最高--->name
  3. doResolveDependency,解析依赖,进行注入
  4. registerBeanDefinition,注册bean定义到beanDefinitionMap属性
  5. preInstantiateSingletons,进行创建bean实例

具体使用操作也是基本类似的

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();  
beanDefinition.setBeanClass(UserService.class);  
defaultListableBeanFactory.registerBeanDefinition("userService",beanDefinition);  
  
UserService userService1 = (UserService) defaultListableBeanFactory.getBean("userService");  
userService1.test();

从他的结构图也能看出来:

Spring源码系列:核心概念解析

AbstractBeanFactory

该类是抽象bean,介绍他主要目的就是getbean时,走的主要逻辑就是该类实现的dogetbean方法(请记住这个重要的方法),所以确实需要关注下,主要方法如下:

  1. doGetBean,获取bean的主要逻辑,没有则创建
  2. getMergedBeanDefinition,bean定义的合并逻辑,主要是将父类beanfactory中的属性被子类覆盖

AbstractAutowireCapableBeanFactory

继承自刚才提到的AbstractBeanFactory,主要方法如下:

  1. autowireByName,按照name注入
  2. autowireByType,根据类型
  3. createBean,创建bean流程,实例化前可以使用BeanPostProcessors后置处理器
  4. createBeanInstance,正在创建bean,这边使用到了之前入门讲过的推断构造器实现实例化
  5. doCreateBean,创建bean,循环依赖、属性填充、初始化
  6. initializeBean,初始化bean,包括初始化前、初始化、初始化后
  7. instantiateUsingFactoryMethod,利用factorymethod初始化bean
  8. invokeAwareMethods,初始化bean时的回调函数Aware接口
  9. populateBean,初始化之前,属性赋值

可以从他的关键方法看出,主要作用就是初始化bean的全过程,也是很重要的类

HierarchicalBeanFactory

这里说下HierarchicalBeanFactory类,他只是一个接口类,但是如果想要使用beanfactory的层次结构,例如获取父beanfactory,那就必须实现HierarchicalBeanFactory类,比如前面说的bean定义的合并逻辑,就需要获取父beanfactory,从而实现父子bean定义的覆盖合并

ApplicationContext

ApplicationContext是个接口,实际上也是一个BeanFactory,不过比BeanFactory
更加强大,它本身并没有太多方法,但是它继承了很多接口,因为接口之间是可以多继承的。

Spring源码系列:核心概念解析

关于他的父接口,这里不做多说明,详情的话请看下子文章(后续更新)。

AnnotationConfigApplicationContext

一看这个类,大家都知道了,我们用的实例全是用这个类去启动我们的spring的,我们看看他的主要方法:

  1. AnnotationConfigApplicationContext,构造器,会初始化DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner;然后开始调用refresh()方法。
  2. register,会使用编程式定义将bean注入spring容器。就如我们的APPConfig
  3. scan,走ClassPathBeanDefinitionScanner的scan,扫描包路径,将声明式的bean注入进spring容器
  4. setBeanNameGenerator,bean名称生成器

ClassPathXmlApplicationContext

主要就是去解析xml配置的bean定义将其注入到spring容器中,功能其实跟AnnotationConfigApplicationContext类似,但是却没有AnnotationConfigApplicationContext强大,比如不能注册BeanDefinition。

BeanPostProcessor

BeanPostProcess表示Bena的后置处理器,可以有多个BeanPostProcessor,我们自己也可以去定义一个BeanPostProcessor;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if ("userService".equals(beanName)) {
            System.out.println("userService");
            return new User();
        }
        System.out.println("MyBeanPostProcessor.postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization");
        return bean;
    }

我们可以通过实现bean的后置处理器,来对某一个bean或者所有bean的进行干预,博主只是随便写了一个,没有什么太大意义。

BeanFactoryPostProcessor

BeanFactoryPostProcessor表示Bean工厂的后置处理器,其实和BeanPostProcessor类似,BeanPostProcessor是干涉Bean的创建过程,BeanFactoryPostProcessor是干涉BeanFactory的创建过程,我们也可以自定义:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("加工beanFactory");
    }
}

FactoryBean

FactoryBean和BeanFactory不是一个东西,大家不要混淆两个概念,BeanFactory是管理我们注入的bean等,而FactoryBean本身也会被Spring管理,一旦Spring知道我们的bean实现了FactoryBean,那么会自动调用getObject方法获取我们自己创建的bean,这个bean完完全全交给我们自己创建了,我们可以这样定义一个FactoryBean:


@Component
public class MyFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        UserService service = new UserService();
        return service;
    }

    @Override
    public Class<?> getObjectType() {
        return UserService.class;
    }

}

但是需要注意的是,这些注入UserService时,是不会有属性依赖注入的,毕竟他没有走bean的生命创建周期。细心的朋友会发现,这根我在配置类中写@bean形式的类有啥区别,现象来讲,他俩都可以被创建出来,但是值得一提的是,FactoryBean创建出来的bean是没走spring定义的bean生命周期的。

MetadataReader、ClassMetadata、AnnotationMetadata

Spring启动时需要扫描指定包路径下的所有类文件来获取需要注入或管理的Bean信息。然而,并非所有类都是需要的,这时可以使用ASM技术来解析类文件的元数据信息,包括类上的注解信息和类的基本信息。ASM技术可以在运行时动态生成和修改Java字节码,从而高效地解析类文件的元数据信息,避免了大量的IO操作和类加载,提高了应用的性能。以下是一个简单的实例:

        SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
        MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.xiaoyu.service.UserService");
        System.out.println(metadataReader.getClassMetadata().getClassName());
        metadataReader.getAnnotationMetadata().getAnnotationTypes().forEach(System.out::println);

结语

通过本文的解析,我们大致了解了Spring框架中的一些关键组件及其用途,这有助于我们在深入理解Spring源码过程中建立起一个整体框架。Spring源码量很大,要真正理解透彻还需要投入大量时间进行细致学习和总结。但如果先对一些关键组件有一个大致的认识,有助于我们进行针对性学习,避免迷失在繁杂的细节中。希望本文能够对读者有一定的帮助,更希望读者在学习Spring源码的过程中,不断总结和提高,并在一定阶段有所突破。祝读者顺利文章来源地址https://www.toymoban.com/news/detail-419498.html

到了这里,关于Spring源码系列:核心概念解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Security系列】一文带你了解权限框架与Spring Security核心概念

    权限框架是软件开发中用于管理 用户权限和访问控制 的工具。在企业或者我们毕设复杂的系统中,不同的用户或角色需要拥有不同的访问和操作权限,以确保系统的安全性和数据完整性。今天我们就讨论一下Java中的安全框架! 在企业的开发中,Spring Security,Shiro都是比较流

    2024年04月16日
    浏览(40)
  • 本文将从云原生的概念、背景知识、Kubernetes架构及核心组件、应用场景、案例研究等方面深入剖析云原生课程的相关知识点

    作者:禅与计算机程序设计艺术 2020年,技术快速发展,云计算火爆。云原生领域也随之蓬勃发展。云原生已经成为大势所趋,大量企业都在逐渐转型云原生应用架构。国内外云服务厂商也纷纷推出基于Kubernetes的服务平台,而Kubernetes又是云原生开源技术体系的一部分。为了帮

    2024年02月07日
    浏览(66)
  • 从零开始学Spring Boot系列-前言

    在数字化和信息化的时代,Java作为一种成熟、稳定且广泛应用的编程语言,已经成为构建企业级应用的首选。而在Java生态系统中,Spring框架无疑是其中最为耀眼的一颗明星。它提供了全面的编程和配置模型,用于构建企业级应用。随着Spring Boot的出现,这一框架变得更加易于

    2024年02月22日
    浏览(59)
  • Spring-底层架构核心概念

    BeanDefinition BeanDefinition表示Bean定义,有很多属性用来描述Bean的特点: class,表示Bean类型 scope,表示Bean作用域,单例或原型等 lazyInit:表示Bean是否是懒加载 initMethodName:表示Bean初始化时要执行的方法 destroyMethodName:表示Bean销毁时要执行的方法 还有很多... 定义Bean的方式主要

    2024年02月08日
    浏览(43)
  • Spring底层架构核心概念

    BeanDefinition表示Bean定义,BeanDefinition中存在很多属性用来描述一个Bean的特点。比如: class,表示Bean类型 scope,表示Bean作用域,单例或原型等 lazyInit:表示Bean是否是懒加载 initMethodName:表示Bean初始化时要执行的方法 destroyMethodName:表示Bean销毁时要执行的方法 还有很多… 在

    2024年02月07日
    浏览(37)
  • 一起学Elasticsearch系列-核心概念

    本文已收录至Github,推荐阅读 👉 Java随想录 微信公众号:Java随想录 开个新的坑,创作关于Elasticsearch的系列文章 首先,让我们简单的了解一下Elasticsearch: Elasticsearch是一个开源的搜索和分析引擎,支持近实时的大数据存储、搜索和分析。它基于Apache Lucene项目,提供全文搜索

    2024年02月01日
    浏览(49)
  • Spring 核心概念之一 IoC

    欢迎来到本篇文章!通过上一篇什么是 Spring?为什么学它?的学习,我们知道了 Spring 的基本概念,知道什么是 Spring,以及为什么学习 Spring。 今天,这篇就来说说 Spring 中的核心概念之一 IoC。 IoC 这个概念对于初学者来说还真不是很好理解,我就是那个理解不了的初学者。

    2024年02月07日
    浏览(37)
  • Spring概述与核心概念学习 -- Spring入门(一)

    为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。 (博客的参考源码以及可以在我主页的资源里找到,如果在学

    2024年02月16日
    浏览(48)
  • 三分钟白话RocketMQ系列—— 核心概念

    目录 摘要 Q1:RocketMQ是什么? Q2: 作为消息中间件,RocketMQ和kafka有什么区别? Q3: RocketMQ的基本架构是怎样的? Q4:RocketMQ有哪些核心概念? 总结 RocketMQ是一个开源的分布式消息中间件。它是一种低延迟、高可用、高可靠、高并发的消息队列系统,用于在分布式系统中进

    2024年02月14日
    浏览(38)
  • Python与Pytorch系列(二) 本文(1.8万字) | 解析Opencv, Matplotlib, PIL | 三者之间的转换 | 三者对JPG和PNG读取和写入 |

    点击进入专栏: 《人工智能专栏》 Python与Python | 机器学习 | 深度学习 | 目标检测 | YOLOv5及其改进 | YOLOv8及其改进 | 关键知识点 | 各种工具教程 推荐网站 : OpenCV Matplotlib Pillow opencv的基本图像类型可以和numpy数组相互转化,因此可以直接调用 torch.from_numpy(img) 将图像转换成 t

    2024年02月03日
    浏览(83)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包