学习记录:DAY20

技术探索之旅:YAML配置,依赖注入、控制反转与Java注解

前言

最近有点懒了,太松懈可不行。为了让自己保持学习的动力,我决定将最近的学习内容整理成博客,目标是让未来的自己也能轻松理解。我会尽量以整体记录的方式呈现,所以一篇博客可能会分几天完成。今天,我们先来研究一下依赖注入和控制反转,顺便把昨天的 YAML 配置映射的博客补充一下。

日程

  • 8点:中午稍微看了一点内容,先来写博客,再看看今天晚上能学到多少东西。
  • 11点:下班吧,复习一会儿。

学习记录

操作系统

  1. 分段存储管理
  2. 段页式管理

学习内容

省流

  1. YAML 配置文件
  2. 依赖注入与控制反转
  3. Java 注解

1. YAML 配置文件

问题背景

在一轮项目中,我将一些配置相关的常量写到了单例里面。这种方法的优点是实现简单,但不利于更改,尤其是在将项目作为 JAR 包部署到服务器时。将配置信息写入 YAML 文件,主要就是为了解决这个问题。

实现方式

主要调用了 Jackson 的 YAML 解析依赖:

<!-- YAML 格式解析器 -->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-yaml</artifactId><version>2.17.1</version>
</dependency>

以我现在的 YAML 配置文件为例:

# Tomcat 相关配置
tomcat:# 端口port: 8080# webapp 目录webappDir: "Anykat-application/src/webapp"# 扫描的目录classesDir: "Anykat-application/target/classes"# Jwt 相关配置
jwt:# Jwt 密钥secretKey:  "ProjectAnykatKaCatIsMyLongLongSecretKeyTo256Bits"# 管理员 Jwt 密钥adminSecretKey: "ProjectAnykatKaCatIsMyLongLongSecretKeyTo256BitsUsingByAdmin"# 有效时间expireTime: 21600000 # 6h

通过一个单例来管理:

public class AppConfig {private TomcatConfig tomcat;private JwtConfig jwt;// 私有静态实例变量private static volatile AppConfig instance;// 私有构造函数防止外部实例化private AppConfig() throws FileNotFoundException {}// 获取单例的静态方法public static AppConfig getInstance() throws FileNotFoundException {if (instance == null) {...}return instance;}
}

在单例实例化时进行加载:

// 加载配置文件
Yaml yaml = new Yaml();
instance = yaml.loadAs(new FileInputStream("config.yml"),AppConfig.class
);
缺点

这种方法的实现比较粗糙简单,它对 YAML 字段的对应有严格要求,且必须有相应的实体类来接收 YAML 映射。因为通过单例进行加载,所以不支持热更新。

改进建议
  • 通过反射和动态代理来生成对应字段的实体类,不依赖硬编码的实体类。
  • 把单例模式换成其他模式,来支持配置的热更新。

2. 依赖注入与控制反转

作用分析

首先,我们来了解一下这是一种什么工作模式:

  • 不直接创建实体类的对象,而是先把实体类交给 IoC 容器管理(控制反转),在需要使用时,再从容器中取出对应的对象(依赖注入)。
  • 对比直接通过 new 创建对象,这样做的好处包括:
    • 生命周期管理:自动处理对象销毁,避免内存泄漏;处理复杂的生命周期(单独实例/共享单例实例)。
    • 依赖关系管理:装配时自动处理依赖的装配;解决循环依赖、嵌套依赖(三层缓冲)。
    • 低耦合度:实例替换;单元测试(mockBean 替换)。
    • 可配置性和灵活性:可以在不修改代码的情况下通过配置改变应用程序行为;支持运行时决定具体实现(如根据环境选择不同实现)。
    • 集中管理:所有对象的创建和依赖关系在一个地方管理;便于维护和了解系统整体结构。
原理分析

Spring Boot 中的依赖注入主要有以下核心功能:

  • 注册组件(类)
  • 管理组件实例
  • 自动解析依赖关系
  • 提供获取 Bean 的接口

工作流程如下:

  1. 组件注册阶段

    • 启动时扫描配置的包路径。
    • 将被注解的类转换为 BeanDefinition 对象。
    • 注册到 BeanDefinitionRegistry(由 DefaultListableBeanFactory 实现):
      • 使用 beanDefinitionMapConcurrentHashMap)存储 Bean 的定义。
      • 维护 beanDefinitionNames 列表保持顺序。
  2. 预处理阶段

    • 执行 BeanFactoryPostProcessor(可修改 BeanDefinition)。
    • 处理一些元数据相关的注解。
    • 预解析依赖关系。
  3. 实例化管理阶段DefaultListableBeanFactory):

    • 按依赖顺序实例化:
      • 通过 createBean() 创建实例。
      • 使用三级缓存解决循环依赖。
      • 依赖注入(@AutowiredAutowiredAnnotationBeanPostProcessor 处理)。
      • 调用初始化方法(@PostConstruct)。
    • 存储单例 Bean 到 singletonObjectsConcurrentHashMap)。
  4. 运行时阶段

    • 处理 getBean() 请求。
    • 管理生命周期(包括销毁过程)。
    • 处理作用域(单例/原型/请求/会话等)。

重要概念

  • BeanDefinition 不等同于 Bean 本身,它是 Bean 的解释。
    • 比如:Bean 是一道要做的菜,BeanDefinition 是这道菜的菜谱。
    • Registry 是管理这些菜谱的管理员。
    • Factory 是负责做菜的那个厨神。

流程图

不存在
单例
原型
请求级
启动SpringBoot应用
组件注册阶段
扫描组件注解
生成BeanDefinition
注册到Registry
存储beanDefinitionMap
维护beanDefinitionNames
预处理阶段
执行BeanFactoryPostProcessor
处理PrimaryDependsOn
构建依赖关系图
实例化阶段
是否单例
检查singletonObjects
调用createBean
三级缓存处理
依赖注入
执行初始化
存入singletonObjects
直接创建实例
运行时阶段
接收getBean请求
作用域类型
返回缓存实例
新建实例
作用域获取
生命周期管理
销毁清理
源码分析

这是不得不品鉴的一环。先 clone 一下 Spring Framework 的源码:Spring Framework 源码。然后我自己慢慢看源码(略过了哈)。

3. Java 注解

在正式编写自己的 BeanFactory 方法之前,先来了解一下关于 Java 注解的基本知识。

Java 提供了一些内置注解:

  • @Override:表示方法覆盖了父类中的方法。
  • @Deprecated:表示元素已过时,不推荐使用。
  • @SuppressWarnings:告诉编译器忽略特定警告。
  • @SafeVarargs:断言方法或构造器不会对其可变参数执行不安全的操作。
  • @FunctionalInterface:表示接口是函数式接口(Java 8)。

而实现自己的注解,则要用到 Java 的元注解:

  • @Target:指定注解可以应用的位置(如 TYPE(类、接口、注解、枚举)、METHOD(方法)、FIELD(字段、常量)等)。
  • @Retention:指定注解的保留策略(SOURCE(源码级,编译时丢弃)、CLASS(类文件,运行时不加载)、RUNTIME(运行时))。
  • @Documented:表示注解应包含在 Javadoc 中。
  • @Inherited:表示子类可以继承父类的注解。
  • @Repeatable:表示注解可以在同一位置重复使用(Java 8)。

示例:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

重要说明
注解的本身没有任何作用,它只是做了一个标记。例如,@Retention(RetentionPolicy.RUNTIME) 以属性表的形式存储在 .class 文件中,在运行时可以通过反射扫描到对应的字段。

结语

真的快把我看麻了,距离能够自己实现一个依赖注入还有很长的路要走,加油吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MCP:人工智能时代的HTTP?探索AI通信新标准

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

首版次误区有哪些?与软件测试报告又有什么联系?

在软件开发与测试领域&#xff0c;"首版次"这一概念关乎软件的版本控制与管理&#xff0c;是确保产品质量和发布节奏的重要环节。首版次&#xff0c;通常是指软件产品第一个对外发布或内部验收的版本号&#xff0c;标志着一次完整开发周期的结束和下一阶段工作的开始…

Laravel+API 接口

LaravelAPI 接口 网课连接&#xff1a;BIlibili. 中文文档. 1.RestFul Api编码风格 一、API设计 修改hosts&#xff0c;C:\Windows\System32\drivers\etc\hosts&#xff0c;增加127.0.0.1 api.lv8.com # Laravel 框架 用这个域名来测试&#xff08;推荐规范&#xff09; 在…

MIT6.S081-lab7前置

MIT6.S081-lab7前置 这部分包含了设备中断和锁的内容 设备中断 之前系统调用的时候提过 usertrap &#xff0c;而我们的设备中断&#xff0c;比如计时器中断也会在这里执行&#xff0c;我们可以看看具体的逻辑&#xff1a; void usertrap(void) {int which_dev 0;if((r_sst…

Linux 下编译BusyBox

一、linux下编译 1.拉取busybox源码 git clone https://github.com/mirror/busybox.git 内容如下 2.配置make&#xff0c;建议在linux下单独开一个终端执行 进入busybox源码目录&#xff0c;使用如下命令 make menuconfig 3.报错 解决办法&#xff1a; 安装ncurses sud…

Element:Cheack多选勾选效果逻辑判断

效果展示 取消子级勾选&#xff0c;父级的勾选效果 代码合集 &#xff08;1&#xff09;组件代码 fromlist.cheackType 类型&#xff0c;permissio表示是权限. fromlist:[{id:1,children:[{...}]},...]传递的数据大致结构 <!-- 操作权限 --><template v-if"…

【3DMax脚本MaxScript开发:创建高效模型虚拟体绑定和材质管理系统,从3DMax到Unreal和Unity引擎_系列第一篇】

3ds Max 脚本开发 3ds Max 脚本开发&#xff1a;创建高效模型虚拟体绑定和材质管理系统3ds Max 插件制作背景&#xff1a;设计思路一、场景节点收集与过滤废话不多说&#xff0c;直接上完整代码&#xff1a;界面定义与基础设置界面控件创建状态变量核心逻辑函数过滤选项改变事件…

【Linux学习笔记】进程替换和自定义shell

【Linux学习笔记】进程替换和自定义shell &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 文章目录 【Linux学习笔记】进程替换和自定义shell前言一.进程程序替换1.1 替换原理1.2 替换函数1.2.1函数解释1.2.2命名理解 二.自主…

【办公类-89-03】20250429AI写的研讨记录,清除格式,统一格式,名字替换。部分加粗,添加页眉

背景需求: 检查自即,需要AI一下院内的五次科研培训记录。 本次用了豆包 豆包写的不错,也是“水字数”的高手 把每次培训内容贴到WORD里 把AI资料贴到WORD里,发现问题: 1、字体、段落什么都是不统一的,需要统一改成宋体小四,1.5倍行距 2、十个研讨人也要改成真人。就找…

unity Orbbec Femto Bolt接入unity流程记录 AzureKinectExamples 插件 使用记录

奥比中光的深度相机Orbbec Femto Bolt是Microsoft的Azure Kinect DK的升级版&#xff0c;根据官网的文档配置环境遇到了一些问题&#xff0c;记录一下。 注意&#xff1a; 官网文档链接&#xff1a;Femto Bolt文档 1、首先连接相机到电脑USB3.0&#xff0c;接通电源&#xf…

聊天室系统:多任务版TCP服务端程序开发详细代码解释

1. 需求 目前我们开发的TCP服务端程序只能服务于一个客户端&#xff0c;如何开发一个多任务版的TCP服务端程序能够服务于多个客户端呢? 完成多任务&#xff0c;可以使用线程&#xff0c;比进程更加节省内存资源。 2. 具体实现步骤 编写一个TCP服务端程序&#xff0c;循环等…

Python3:装饰器、生成器与迭代器

Python3&#xff1a;装饰器、生成器与迭代器 一、&#x1f3ad; 装饰器&#xff1a;给函数穿上"魔法外衣"装饰器基本概念为装饰器添加参数传递功能带参数的装饰器functools.wraps&#xff1a;保留原函数的元信息实用装饰器示例1. 计时器装饰器2. 缓存装饰器(Memoizat…

SQL命令一:SQL 基础操作与建表约束

目录 引言 一、SQL 基础命令 &#xff08;一&#xff09;数据库相关操作 &#xff08;二&#xff09;表格相关操作 &#xff08;三&#xff09;MySQL 常用数据类型 二、增删改查&#xff08;CRUD&#xff09;操作 &#xff08;一&#xff09;增加数据 &#xff08;二&a…

Windows 桌面个性高效组件工具

软件介绍 Widgets 这款基于 Vue3 构建的开源 Windows 桌面小部件工具超实用。 其多样化组件库涵盖超 20 种&#xff0c;从倒计时、打工进度等实用工具&#xff0c;到抖音热榜等实时资讯组件应有尽有&#xff0c;各组件独立运行&#xff0c;满足多场景需求。 高度自定义布局支持…

PCB入门指南:从电阻到常见电路的全解析

知识点1【电阻】 常见的是 色环电阻和贴片电阻 1、色环电阻 色环电阻&#xff0c;早期是碳膜电阻&#xff0c;精度不是很高&#xff0c;一般是4个色环&#xff0c;红 橙 黄 绿 蓝 紫 灰 白 黑&#xff0c;每个颜色代表一个阻值 后期是金属膜电阻&#xff0c;5个色环&#x…

论文阅读的三个步骤

论文阅读的三个步骤 方法说明链接&#xff1a;https://www.academia.edu/4907403/How_to_Read_a_Paper 方法框架如下

Centos 7 ssh连接速度慢(耗时20秒+)

作系统&#xff1a;centos7.9 现象突然间通过 ssh、xshell等客户端工具连接时&#xff0c;连接速度缓慢&#xff0c;需要耗时20秒左右才能连接上 排查思路&#xff1a; 1. 查看操作系统日志 从系统日志里看到较多的错误&#xff0c;这个可能是一个bug &#xff08;现象类似&a…

通过脚本自动检查项目中全局的中文

现在越来越多的公司在做出海项目&#xff0c;出海项目首先要解决的就是语言国际化的问题&#xff0c;有很多如l18n、l10n的工具可以用&#xff0c;这些工具可以提供解决方案&#xff0c;但是不能约束开发者的开发行为。开发者仍然可能在代码中存留没有做过国际化处理的部分&…

软件分析师-第三遍-章节导图-13/14

系统设计&#xff0c;按步骤分&#xff1a;概要设计、详细设计。另一种分类方式&#xff1a;按设计内容和设计方法分。设计内容&#xff1a;处理流程、输入/输出原型、人机交互。设计方法&#xff1a;结构化、面向对象、设计模式。 软件实现&测试&#xff0c;分为实现、测…

通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎|文献速递-深度学习医疗AI最新文献

Title 题目 Hashimoto’s thyroiditis recognition from multi-modal data via globalcross-attention and distance-aware training 通过全局交叉注意力机制和距离感知训练从多模态数据中识别桥本氏甲状腺炎 01 文献速递介绍 桥本氏甲状腺炎&#xff08;HT&#xff09;&a…