知识点:
1.使用utillist进行配置
知识点 |
核心内容 |
重点 |
Spring框架中utl名称空间创建List |
通过utl名称空间创建并管理集合对象,实现数据复用 |
utl list与普通list赋值的区别; 名称空间引入方法 |
无参构造器使用规则 |
当类中没有其他构造器时,默认无参构造器可不写;若有其他构造器则必须显式定义无参构造器 |
构造器覆盖机制; 显式定义的必要性 |
XML名称空间引入 |
使用alt+enter自动引入或手动添加xmlns:util声明 |
工具兼容性问题处理; schema location配置 |
集合属性注入 |
通过<util:list>定义共享集合,使用ref属性引用 |
数据复用实现方式; value与ref的使用场景 |
BookStore案例演示 |
包含bookList属性的类配置,展示集合注入的两种实现方式 |
XML配置语法对比; 运行时验证方法 |
2.属性级联赋值配置
知识点 |
核心内容 |
重点 |
级联属性赋值 |
通过Spring IOC容器直接对对象属性的属性赋值(如employee.department.name) |
配置语法:<property name="department.name" value="JAVA开发部门"/> |
对象关联配置 |
在配置主对象(如employee)时引用关联对象(如department)并级联赋值 |
底层原理:调用关联对象的setter方法 (如department.setName()) |
XML配置示例 |
演示employee与department的级联配置,动态设置部门名称 |
易错点:需确保关联对象已实例化且属性可访问(如department需有无参构造器) |
测试验证 |
通过输出employee对象验证级联赋值结果(如部门名称显示为JAVA开发部门) |
关键代码:employee.getDepartment().getName() |
3.通过静态工厂获取Bean
知识点 |
核心内容 |
重点 |
静态工厂模式 |
通过工厂类返回指定对象,替代直接配置方式 |
工厂类与普通Bean配置的区别 |
静态代码块特性 |
类加载时执行且只执行一次,用于初始化 |
静态代码块与普通代码块执行时机差异 |
工厂方法配置 |
class属性需指定工厂类全路径,factory-method指定方法 |
容易混淆普通Bean配置的class属性用法 |
对象获取机制 |
通过constructor-arg指定工厂内具体对象key |
多对象管理时key的匹配规则 |
单例验证 |
同一ID多次获取为同一对象(静态工厂特性) |
与原型模式(prototype)的作用域区别 |
4.通过实例工厂获取Bean
知识点 |
核心内容 |
重点 |
静态工厂与实例工厂的区别 |
静态工厂通过类直接调用静态方法获取对象,无需实例化工厂类;实例工厂需先创建工厂实例,再通过实例方法获取对象 |
静态工厂方法为static,实例工厂方法需依赖对象调用 |
实例工厂配置流程 |
1. 配置实例工厂Bean 2. 在目标Bean中通过factory-bean指定工厂实例 3. 通过factory-method指定方法 4. 用constructor-arg传递参数 |
必须显式配置工厂实例Bean |
对象作用域对比 |
静态工厂返回的对象始终为同一实例(单例);实例工厂根据工厂实例不同可能返回不同对象 |
实例工厂的对象作用域与工厂实例绑定 |
配置示例代码 |
xml <bean id="myInstanceFactory" class="com.factory.MyInstanceFactory"/> <bean id="monster02" factory-bean="myInstanceFactory" factory-method="getMonster"> <constructor-arg value="monster03"/> </bean> |
factory-bean与factory-method需配对使用 |
关键验证逻辑 |
同一实例工厂多次调用返回相同对象;不同实例工厂返回不同对象(即使参数相同) |
对象一致性取决于工厂实例而非配置ID |
5.通过FactoryBean获取Bean
知识点 |
核心内容 |
重点 |
Factory Bean机制 |
通过实现FactoryBean接口创建工厂Bean,可定制对象创建逻辑 |
getObject()与getObjectType()方法必须重写 |
泛型指定 |
FactoryBean需指定泛型类型决定生产对象类型 |
泛型类型与实际返回对象类型必须匹配 |
单例控制 |
isSingleton()方法决定返回对象是否为单例 |
默认false(原型模式),需显式设置为true |
对象获取流程 |
1. 配置class为FactoryBean全类名; 2. 通过property指定key值; 3. 容器调用getObject()返回目标对象 |
class属性配置的是工厂Bean而非目标Bean |
Map结构存储 |
使用HashMap预存多个对象实例 |
key-value需与配置的property严格对应 |
配置示例 |
xml<bean id="myMonster05" class="com.MyFactoryBean"><property name="k" value="monster04"/> |
k属性对应工厂Bean的setK()方法 |
6.Bean配置信息重用
知识点 |
核心内容 |
重点 |
Spring IOC容器继承机制 |
通过parent属性实现bean配置信息重用,避免重复配置相同属性 |
parent属性引用方式 vs 直接复制配置 |
抽象bean配置 |
通过abstract="true"声明仅供继承的模板bean,类似Java抽象类 |
抽象bean不可实例化 vs 普通bean可实例化 |
属性继承验证 |
子bean自动继承父bean所有属性值(如monster11继承monster10) |
继承后属性覆盖规则需注意 |
配置复用场景 |
适用于多bean共享相同基础属性的场景(如多个monster对象) |
属性继承 vs 对象组合的选择 |
异常处理案例 |
尝试实例化抽象bean会抛出BeanIsAbstractException |
抽象bean仅作为配置模板的设计意义 |
7.Bean创建顺序(1)
知识点 |
核心内容 |
重点 |
Spring IOC容器中Bean的默认创建顺序 |
默认按照XML/配置文件的书写顺序从上到下创建Bean对象 |
配置顺序决定初始化顺序,无依赖关系时严格按代码先后执行 |
depends-on属性强制改变创建顺序 |
通过depends-on="targetBeanId"显式声明依赖关系,优先初始化被依赖的Bean |
即使被依赖的Bean配置在后方,仍会逆向触发初始化 |
依赖关系的实际应用场景 |
班级(Class)需先于学生(Student)创建,确保引用有效性 |
业务逻辑中存在强依赖时必须使用depends-on |
验证方法(构造器输出日志) |
在无参构造器中打印日志,通过控制台输出观察Bean初始化顺序 |
构造器执行顺序=Bean创建顺序,需注意日志干扰项 |
8.Bean创建顺序(2)
知识点 |
核心内容 |
重点 |
Spring IOC容器中bean的创建顺序 |
1. 默认按配置顺序创建bean; 2. 引用关系的处理是最后阶段完成; 3. 容器会将所有bean先实例化再处理依赖 |
配置顺序≠依赖解析顺序; 即使被引用的bean后配置也不会导致空引用 |
依赖注入的时序问题 |
1. 容器采用两阶段处理: - 第一阶段:实例化所有bean; - 第二阶段:处理属性注入; 2. 通过BeanDefinitionMap维护依赖关系 |
初学者容易误解为"配置在前面的bean会先被完整初始化" |
构造器与setter方法的执行时机 |
1. 构造器在bean实例化阶段执行; 2. setter方法在依赖注入阶段执行; 3. 实验验证: - 构造器输出先于setter方法 |
构造器注入与setter注入的时序差异 |
配置顺序灵活性 |
1. bean配置顺序可任意调整; 2. 不依赖depends-on也能正确处理循环依赖; 3. 底层通过三级缓存解决依赖循环 |
与传统的new对象方式有本质区别 |
IOC容器的整体性思维 |
1. 容器将所有bean定义作为整体处理; 2. 采用图论算法解析依赖关系; 3. 最终保证所有依赖关系正确建立 |
理解"容器即工厂"的设计哲学 |
9.Bean的单例和多实例(1)
知识点 |
核心内容 |
重点 |
Spring IOC容器的单例与多例 |
默认情况下,Spring IOC容器按单例模式创建bean对象,即整个容器中只有一个实例;通过scope="prototype"可配置为多例模式,每次getBean()返回新对象。 |
单例与多例的配置区别:singleton(默认)vs prototype;单例对象的生命周期与容器一致,多例对象每次独立创建。 |
单例模式的实际表现 |
单例模式下,多次调用getBean()返回同一对象(通过哈希值验证)。 |
需注意单例对象的线程安全问题及状态管理。 |
多例模式的实际表现 |
配置scope="prototype"后,每次getBean()触发构造器执行,返回新对象(哈希值不同)。 |
多例适用于需要隔离状态的场景,但需注意资源开销。 |
代码演示与验证 |
通过Cat类构造器输出验证单例/多例效果:单例模式仅输出一次构造信息,多例模式每次调用均输出。 |
易混淆点:属性相同≠对象相同(多例模式下属性值相同但对象不同)。 |
scope属性的语义 |
scope直译为“范围”,单例(singleton)即容器范围内唯一,多例(prototype)即每次获取均为原型的新实例。 |
需理解prototype的原型设计模式背景。 |
10.Bean的单例和多实例(2)
知识点 |
核心内容 |
重点 |
单例模式默认行为 |
默认在启动容器时创建单例对象,根本原因并非因为是单例,而是lazy-init默认值为false |
单例≠必然提前创建,需结合lazy-init属性判断 |
prototype多例机制 |
配置scope=prototype后,对象在getBean时才会创建,每次调用生成新实例 |
多例对象不存入单例池,创建时机与单例模式本质差异 |
懒加载配置 |
单例模式下设置lazy-init=true会延迟创建,首次getBean时才初始化 |
懒加载仅影响创建时机,不影响单例性质(后续调用仍取同一实例) |
prototype与懒加载关系 |
多例模式下lazy-init属性无效(无论true/false均在getBean时创建) |
需特别注意多例模式天然具有"懒加载"特性 |
单例模式设计权衡 |
默认非懒加载单例以空间换时间,提前创建可能未使用的对象但提升获取效率 |
特殊场景(如事务管理)才需要配置懒加载 |
11.Bean的生命周期
知识点 |
核心内容 |
重点 |
Bean生命周期 |
构造器→set方法→init方法→使用→destroy方法 |
执行顺序和配置方式是关键 |
构造器执行时机 |
JVM创建对象后首先执行构造器 |
构造器调用时对象已在堆内存存在 |
属性注入机制 |
通过set方法完成属性赋值 |
必须提供set方法才能注入 |
init方法配置 |
在bean标签通过init-method指定 |
方法名可自定义,需在配置中声明 |
destroy方法触发 |
容器关闭时自动调用 |
必须显式关闭容器才会触发 |
接口编程实践 |
ConfigurableApplicationContext提供close方法 |
接口引用与实现类方法的访问问题 |
生命周期图示 |
构造→注入→初始化→使用→销毁 |
set方法执行后才调用init方法 |
方法执行控制权 |
init/destroy方法由Spring容器控制时机 |
程序员只负责编写逻辑和配置声明 |
12.配置Bean后置处理器(1)
知识点 |
核心内容 |
重点 |
bin生命周期 |
初始化方法和销毁方法的调用时机与作用 |
初始化方法在容器启动时调用,销毁方法在容器关闭时调用 |
bin后置处理器 |
在初始化方法前后调用的特殊对象,可对bin进行修改处理 |
postProcessBeforeInitialization和postProcessAfterInitialization的区别 |
后置处理器实现 |
需实现BeanPostProcessor接口并重写两个关键方法 |
方法参数中object bean和beanName的含义与用途 |
后置处理器调用时机 |
在bin的init方法前后分别调用对应方法 |
与setter方法执行顺序的关系 |
AOP概念引入 |
后置处理器是理解AOP(面向切面编程)的基础 |
后置处理器与切面编程的关联性 |
实践验证方法 |
通过输出日志验证后置处理器的调用流程 |
如何观察bin对象在处理器中的状态变化 |
13.配置Bean后置处理器(2)
知识点 |
核心内容 |
重点 |
后置处理器配置 |
演示如何通过新建容器配置文件配置后置处理器,避免日志过多干扰 |
后置处理器必须实现特定接口才能生效 |
后置处理器触发时机 |
在初始化方法之前(postProcessBeforeInitialization)和之后(postProcessAfterInitialization)触发 |
注意后置处理器未配置时不会触发任何方法 |
对象生命周期 |
完整展示对象创建流程:构造器→set方法→初始化方法→使用→销毁方法 |
初始化与销毁方法的配置方式 |
容器隔离性 |
不同配置文件(beans/beans02.xml)创建的容器相互独立 |
后置处理器只对所在容器的对象生效 |
后置处理器作用范围 |
配置后会自动作用于容器内所有对象 |
注意处理器方法中接收的对象是同一个实例(通过哈希值验证) |
调试技巧 |
通过新建干净配置文件简化调试,使用toString输出对象状态 |
关键点:处理器方法执行时对象已完成属性注入但未初始化 |
14.配置Bean后置处理器(3)
知识点 |
核心内容 |
重点 |
后置处理器执行机制 |
底层通过AOP机制实现,依赖反射+动态代理 |
方法触发原理(切面编织)与普通方法调用的区别 |
后置处理器作用范围 |
对IOC容器中所有对象生效(如house、monster等) |
作用对象是否包含懒加载实例(仅非懒加载生效) |
应用场景 |
统一处理日志、权限校验、安全验证、事务管理 |
与单一对象处理的代码差异(切面编程范式) |
动态修改案例 |
通过instanceof判断类型,强制将house对象名称改为“上海豪宅” |
运行期修改与配置期修改的优先级冲突 |
底层实现预告 |
后续将手动实现反射+代理+容器+注解机制 |
AOP与IOC容器的耦合关系 |