服务器部署架构图(服务器部署架构图怎么做)

服务器部署架构图(服务器部署架构图怎么做)本文将对 Spring IoC 容器的仿写进行剖析 梳理仿写过程中需要解决的问题 并附全部仿写代码进行说明教学 本文的仿写中不引用任何外部类 纯手动实现简要 IoC 控制反转执行流程 想要顺利并且理解的仿写一个 IoC 框架 在动手前应该先理清要解决的问题 或者说 IoC 框架的执行流程 笔者将 IoC 执行流程大致归纳为了以下几个步骤 对指定包路径进行扫描 找出所有添加了 IoC 注解的目标类

大家好,我是讯享网,很高兴认识大家。



本文将对Spring IoC容器的仿写进行剖析,梳理仿写过程中需要解决的问题,并附全部仿写代码进行说明教学,本文的仿写中不引用任何外部类,纯手动实现简要IoC控制反转执行流程。

想要顺利并且理解的仿写一个IoC框架,在动手前应该先理清要解决的问题,或者说IoC框架的执行流程。

笔者将IoC执行流程大致归纳为了以下几个步骤:

  1. 对指定包路径进行扫描,找出所有添加了IoC注解的目标类。
  2. 获取目标类的信息,Class对象以及类名beanName,并将其封装以便后续使用。
  3. 根据封装好的信息类动态创建bean对象。
  4. bean的自动装载。

若依部署架构图图_ioc
讯享网

以上四步是IoC容器仿写的大概流程,也基本是Spring IoC运作的大致流程,下文将对具体的工作进行介绍和分析。

本部分代码解释说明性质的文字都包含在注释中,重点关注代码注释部分。

准备测试类

首先准备测试类,非必须,本部分可以跳过,读者仿写时可自行设计,笔者仿写完整测试类代码如下(为便于理解,给出的是未添加任何注解版本):

User类:

Role类:

Relationship类:

准备IoC容器入口类

准备一个AnnotationApplicationContext,在本类中完成上文中阐述的四个步骤,实际分步骤测试时,直接准备一个主类在其main方法下创建AnnotationApplicationContext对象测试即可。

AnnotationApplicationContext类结构如下(省略了方法内的内容,下文中会给出):

首先要进行扫描包,此步骤只负责将目标路径下的所有类,即所有.class文件保存,以便后续使用,判断类是否有IoC注解的步骤整合到下一步

笔者仿写时单独准备了一个工具类专门用于包扫描,工具类PackageScanner代码如下:

扫包工具类总结

在工具类PackageScanner中

  • getClasses(String)方法起预处理作用。负责将类名转换为包名,并在判断传入包名是本地文件后调用findLocalClasses(String)。
  • findLocalClasses(String)方法实际扫描包并保存.class文件。本方法递归调用,遇到文件夹则继续调用查找,将所有.class文件保存到一个Set集合中。

关于File部分的说明

非核心部分,只是为了更好理解代码,可忽略。

文中使用了File类中包含的方法listFiles,该方法需要传入一个文件拦截器FileFilter,并且返回一个File[]数组,本文中没有接受该数组,因为在判断过程中就已经可以将.class文件加入Set集合了。

FileFilter是一个接口,接口中只有一个accept方法需要实现,该方法返回值类型为boolean,重写accept方法时需要写出判断逻辑,因为File.listFiles方法就是依靠accept方法的返回值来判断文件是否要添加到File[]数组中。本文直接在accept中判断文件类型,如果为文件夹则递归调用findLocalClasses(String)方法向下查找,如果是.class文件则添加到Set集合。

File中的listFiles方法源码如下:

本部分操作均在AnnotationApplicationContext的getBeanDefinitions(String)方法下完成。

@Component注解

此处模仿Spring IoC,在目标路径下,打上了@Component注解注解的类表示该类交由IoC容器管理,在SpringBoot中经常使用的@Service、@Repository等注解与本文实现的原理大致相同,只是针对不同功能的类有不同的处理,本文只实现@Component。

笔者仿写@Component注解中value值设置了默认值,为的就是在使用@Component注解时,可以使用@Component(“xxxx”)指定beanName,也可以直接使用@Component使用默认值,直接使用时会将类名首字母小写作为默认beanName,处理详见下文。

@Component注解代码如下:

使用示例如下:

BeanDefinition类

BeanDefinition类用于保存每个受管对象的Class对象和类名beanName。

代码如下:

将目标类封装为BeanDefinition

getBeanDefinitions(String)方法中会先调用扫包工具类获取目标路径下的所有.class文件的Class对象,并使用反射技术获取每个Class类对象的注解,如果发现包含@Component注解,说明该对象应交给IoC容器管理,将Class和beanName封装成BeanDefinition添加到Set集合,最终方法返回Set集合。

getBeanDefinitions(String)方法代码如下:

我们现在获取了目标路径下的所有受管对象的必要信息,现在可以开始根据这些信息创建bean对象了,本部分操作全部在AnnotationApplicationContext的createObject(Set<BeanDefinition>)方法下完成。

@Value注解

在创建bean对象时,开发人员期待可以对对象进行初始化操作,仍然通过注解+反射实现这种操作, 详细见下文。

@Value注解代码如下:

@Value注解代码中可以窥见一个问题,就是我们的value值是被写死为String的,因此处理时需要判断目标字段的类型并进行正确的类型转换。

使用示例如下:

创建bean对象

实现过程中,由于只探讨/仿写IoC核心部分,笔者对两个细枝末节的地方进行了简化。

  • 默认bean对象均使用单例模式。
  • 对于@Value注解,只处理了Long的类型转换,并且没有添加任何关于传入值的判断,期望使用人员每次传入的值都是合理正确的。Long类型除外的类型转换与本文的Long类型处理完全一致。

createObject(Set<BeanDefinition>)方法代码如下:

到了这一步,我们成功创建了目标类的对象,并且为部分字段做了初始化处理,bean对象已经接近可以使用了,此部分需要解决最后一个问题,即将bean注入到其他bean中,bean的自动装载。翻译成人话就是,我们的bean对象中可能会引用其他的bean对象,我们需要对这部分对象进行初始化处理(注入)。

Spring中提供了两种方法进行bean注入

  • byName:顾名思义就是直接通过指定beanName注入。
  • byType:顾名思义就是查找匹配的类型进行bean注入。

本部分操作全部在AnnotationApplicationContext的autowireObject(Set<BeanDefinition>)方法下完成。

@Qualifier注解

先从较为简单的byName入手,下文方法代码内读者也可以先挑读Qualifier部分。

@Qualifier注解代码如下:

使用示例如下:

@Autowired注解

@Autowired注解模仿Spring IoC添加一个判断是否必要注入的字段required,默认false不需要。

@Autowired注解代码如下:

使用示例如下:

自动装载

autowireObject(Set<BeanDefinition>)方法代码如下:

至此我们的IoC框架的简单仿写已经彻底完成,从零手动实现了控制反转,下面演示代码的测试。

若依部署架构图图_容器_02

最总测试时entity类下三个用于测试的模拟类代码如下:

User类:

Role类:

Relationship类:

Main类代码准备如下:

打印结果如下:

由打印结果可见我们从零仿写的IoC成功完成了对象的管理、注入等工作,除展示的测试部分除外,剩余各部分代码笔者均已测试无误。

小讯
上一篇 2025-05-11 10:53
下一篇 2025-06-17 11:23

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/160433.html