学习日记-spring-day35-6.23
知识点:
1.实现简单基于XML配置程序 Dom4j回顾
知识点 | 核心内容 | 重点 |
DOM Forge | 用于解析XML文件(如web.xml),涉及Document对象、根元素获取及子元素遍历 | XML解析流程(SAXReader→Document→rootElement→子节点) |
Tomcat底层实现 | 手动模拟Tomcat机制,解析web.xml初始化容器 | init方法中的路径处理与元素遍历逻辑 |
螺旋递增学习模式 | 前后知识点关联 | 回顾students.xml解析案例 |
代码复用 | 复用历史代码(如SAXReader解析工具) | 类路径获取与文档对象构建的代码逻辑 |
2.实现简单基于XML配置程序 代码实现(1)
知识点 | 核心内容 | 重点 |
Spring容器简单实现机制 | 通过DOM解析XML配置文件并反射生成对象 | 单例对象池使用ConcurrentHashMap存储 |
DOM4J解析XML | 获取类路径→创建SAXReader→获取Document对象→提取根元素 | 节点属性获取顺序与XML结构对应关系 |
反射机制应用 | 通过类全路径创建对象实例 | 属性注入时需注意类型转换(如String转Integer) |
项目依赖管理 | JAR包引入的两种状态(已识别/未识别) | Project Structure中Add as Library关键操作 |
代码复用原则 | 合理复用历史代码的实践方法 | 路径处理时需注意相对路径与绝对路径区别 |
异常处理策略 | 构造器异常直接向上抛出 | 配置文件加载失败的常见原因排查 |
测试驱动开发 | 通过分段输出验证各环节数据准确性 | XPath表达式与elements()方法的选择 |
3.实现简单基于XML配置程序 代码实现(2)
知识点 | 核心内容 | 重点 |
反射机制 | 通过Class.forName()获取类对象,使用newInstance()创建实例 | 反射创建的对象属性为默认值,需手动赋值 |
Spring容器流程 | 1. 解析XML配置 2. 反射创建对象 3. 属性赋值 4. 存入单例池 | bin ID与对象属性ID的区别 |
对象属性赋值 | 可通过反射getDeclaredMethods()遍历并调用invoke()赋值 | 实际Spring底层通过动态机制(非硬编码)实现 |
单例池管理 | 使用singletonObjects.put(id, object)存储实例 | 容器ID vs 对象属性ID的区分 |
简化实现目的 | 聚焦核心流程(解析→创建→赋值→存储),暂不处理BeanDefinition等复杂逻辑 | 后续结合AOP/IOC进阶完善 |
4.Spring原生容器结构梳理
知识点 | 核心内容 | 重点 |
Spring容器底层结构 | IOC容器类型为ClassPathXmlApplicationContext,包含BeanDefinitionMap存储Bean配置信息 | BeanDefinitionMap与单例池singletonObjects的关系 |
BeanDefinition存储方式 | 通过ConcurrentHashMap的Node数组(默认512大小)存储,包含Bean的ID、类名、懒加载等属性 | 哈希冲突处理(next指针链表结构) |
单例池机制 | DefaultListableBeanFactory中的singletonObjects(ConcurrentHashMap类型)缓存已实例化的单例Bean | 初始化顺序(系统默认Bean vs 配置Bean) |
属性注入结构 | PropertyValues通过ArrayList存储Bean属性(如monsterId、name等) | XML配置与实际对象属性的映射逻辑 |
Debug分析技巧 | 通过断点追踪BeanDefinitionMap和singletonObjects的实时状态 | 容器启动阶段(Bean定义加载 vs 实例化阶段) |
5. 例题:不指定ID问题
题目解析:
-
配置情况:在beans.xml中注入2个Monster对象但未指定id属性
-
问题1:运行是否会报错
-
问题2:若不报错如何获取自动分配的id
-
解题要点:
-
配置差异:两个Monster对象的属性值存在明显区别(monsterId分别为1010和666,name和skill值也有不同)
-
关键考察:Spring容器对未指定id的bean的处理机制
-
获取方法:需要通过特定方式获取容器自动生成的bean名称
-
-
注意事项:
-
这是故意设计的特殊场景,实际开发中通常应显式指定id
-
需要理解Spring底层容器结构才能正确解答
-
6.例题解答
知识点 | 核心内容 | 重点 |
Spring容器ID分配机制 | 未显式分配ID时,系统会按全类名#序号规则自动分配(如com.example.Monster#0) | 自动分配规则 vs 显式ID配置 |
Debug验证方法 | 通过断点查看beanDefinitionMap中的存储结构,验证自动ID分配规则 | 容器结构查看技巧 |
自动分配ID获取方式 | 使用getBean("全类名#0")获取首个未显式配置ID的bean | 动态获取与静态配置的区别 |
实际开发建议 | 演示场景故意移除ID配置,但生产环境必须显式配置 | 演示与实际应用差异 |
对象属性验证 | 通过输出monster01.getId()验证自动分配bean的属性值正确性 | 对象属性与容器ID的关联 |
7. 例题:配置Car对象
题目解析
-
练习目标:创建一个Car类并通过Spring IOC容器管理该对象
-
具体要求:
-
创建Car类,包含三个属性:id、name、price
-
编写IOC容器配置文件(XML格式)
-
在配置文件中定义Car对象的bean
-
通过Java程序从容器获取该bean并输出
-
-
实现步骤:
-
类定义:创建Car类时应包含完整属性及getter/setter方法
-
XML配置:
-
使用<bean>标签定义Car对象
-
通过<property>标签为各属性赋值
-
-
容器操作:
-
使用ApplicationContext接口获取容器实例
-
调用getBean()方法获取Car对象实例
-
-
-
注意事项:
-
属性赋值需遵循Spring的依赖注入规范
-
配置文件路径需与Java代码中的路径一致
-
bean的id/name需与getBean()参数匹配
-
-
底层原理:
-
练习涉及Spring原生容器的基本结构
-
通过XML配置实现对象创建和属性注入
-
演示了IOC控制反转的基本实现方式
-
8.例题解答
知识点 | 核心内容 | 重点 |
Java类创建与配置 | 新建Car类,包含id、name、price属性,提供全属性构造器和无参构造器 | 无参构造器必要性(容器反射依赖默认构造器) |
Spring IoC容器配置 | 通过XML文件(car.beans)配置Car对象属性(如id="car01", name="宝马", price=1000000) | 配置文件路径与ID匹配(需与代码中getBean调用一致) |
属性注入与输出验证 | 通过getBean获取配置的Car对象,并输出属性值(如car01.getName()返回"宝马") | 属性值注入格式(XML中property标签的value赋值) |
调试与异常处理 | 演示移除无参构造器后的报错场景,强调错误原因 | 异常类型识别(BeanCreationException) |
9.Spring配置Bean的基本介绍
知识点 | 核心内容 | 重点 |
Spring IOC | 依赖注入的多种形式与实现原理 | IOC容器的工作机制 vs 传统对象创建方式 |
Bean管理 | 创建Bean对象与属性注入的多种方式 | XML配置与注解方式的优先级差异 |
XML配置 | 基础用法与高级配置形式(如复杂属性注入) | <bean>标签的scope属性理解 |
注解配置 | @Component、@Autowired等核心注解 | 注解扫描范围的配置陷阱 |
配置方式对比 | XML的显式声明 vs 注解的隐式装配 | 混合使用时的冲突解决 |
10.通过类型来获取Bean
知识点 | 核心内容 | 重点 |
基于XML配置的Spring IOC容器 | 讲解通过XML配置Spring Bean的两种方式:ID获取和类型获取 | 类型获取的局限性(同类Bean需唯一) |
通过ID获取Bean | 使用getBean(String id)方法,需在XML中明确配置Bean的ID属性 | 容器底层结构分析与ID命名规范 |
通过类型获取Bean | 使用getBean(Class<T> type)方法,要求同类Bean唯一 | NoUniqueBeanDefinitionException异常场景演示 |
单例模式应用场景 | 控制器(Controller)或服务层(Service)等单线程单实例场景推荐使用类型获取 | 多实例需求时需改用ID获取 |
XML配置语法细节 | Bean的默认ID生成规则(全类名#编号)与显式ID覆盖 | 未保存配置导致的问题演示 |
11.Spring底层给bean对象属性赋值使用的是setter方法
知识点 | 核心内容 | 重点 |
Spring容器属性赋值机制 | 底层通过setter方法完成属性注入 | 必须提供对应属性的setter方法否则报错 |
反射赋值原理 | Spring通过反射调用setter方法实现属性赋值 | 方法命名规范(set+属性名首字母大写) |
错误验证案例 | 移除Car类的setName方法导致容器初始化失败 | 错误信息关键字段"no setter method" |
设计约束 | 所有需要依赖注入的属性必须配套setter方法 | 方法可见性要求(public修饰符) |