知识点:
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修饰符) |