学习日记-spring-day44-7.9
知识点:
1.抛出问题 Spring AOP
知识点 | 核心内容 | 重点 |
Spring AOP实现原理 | 通过@Aspect注解定义切面类,结合@Before/@After等通知类型实现方法拦截 | 注解配置遗漏(需@EnableAspectJAutoProxy启用自动代理) |
切面类配置 | 使用@Component+@Aspect声明切面,通过表达式或直接指定目标方法 | 前置通知(@Before)与最终通知(@After)执行顺序差异 |
动态代理机制 | 原生Spring通过后置处理器解析AOP注解并生成代理对象 | 代理对象与原始Bean的调用链路区别 |
注解驱动开发 | @EnableAspectJAutoProxy启用基于注解的AOP功能 | 未添加该注解导致切面失效的高频错误 |
通知类型实践 | 演示前置、返回、异常、最终通知的代码编写与输出验证 | 异常通知(@AfterThrowing)仅触发条件 |
2.简析Spring AOP 和 BeanPostProcessor关系
知识点 | 核心内容 | 重点 |
AOP与BeanPostProcessor关系 | 代理对象生成机制:Bean创建后根据AOP处理决定返回代理对象或原生Bean | 为什么SmartDog对象在after后置处理器调用时变成代理对象 |
EnableAspectJAutoProxy注解 | 启用切面自动代理功能,引入AspectJAutoProxyRegistrar类 | 注解底层与BeanPostProcessor的关联机制 |
AnnotationAwareAspectJAutoProxyCreator | 核心代理创建器,继承自BeanPostProcessor接口 | 类图继承关系与动态代理技术结合点 |
Spring底层实现机制 | 分六阶段实现: 1.获取BeanClass 2.封装BeanDefinition 3.单例/多例处理 4.依赖注入 5.后置处理器 6.AOP机制 | 单例池预先创建 vs 多例动态生成的区别 |
动态代理技术应用 | AOP通过代理对象实现方法拦截,底层使用反射调用机制 | 原生类型与代理类型的转换时机 |
学习深度建议 | 掌握Bean生命周期管理、依赖注入、AOP代理生成即可满足面试需求 | 框架复杂度与学习深度的平衡点 |
3.补充说明
知识点 | 核心内容 | 重点 |
AOP代理机制 | 解释为何smart dog对象在后置处理器中变成代理对象,而user action和user dao没有 | 区分原生类型和代理对象的转换条件 |
切面编程原理 | 当类方法被切面切入时,Spring会通过动态代理生成代理对象 | 理解切面配置与代理对象生成的因果关系 |
后置处理器作用 | after initialization阶段决定是否将Bean包装为代理对象 | 后置处理器对所有Bean的处理差异 |
接口代理与类代理 | 演示即使不按接口注入,被切入的类仍会生成代理对象 | CGLIB与JDK动态代理的选择条件 |
切面配置验证 | 通过注销切面配置证明代理对象生成与切面存在直接关联 | 切面注解的生效范围实验 |
懒加载机制 | 单例Bean的初始化时机与代理对象生成的关系说明 | 懒加载对AOP代理的影响 |
4.Spring整体架构分析(1)
知识点 | 核心内容 | 重点 |
Spring容器创建初始化流程 | 1. 扫描包获取Bean的Class对象并排除非Bean类; 2. 将Bean信息封装到BeanDefinition对象并存入BeanDefinitionMap; 3. 根据单例/多例判断实例化并存储到单例池(SingletonObjects) | BeanDefinition的作用; 单例池与原型模式的区别 |
Spring容器getBean实现机制 | 1. 初始化完成后通过getBean方法获取对象; 2. 底层依赖反射和BeanDefinition信息动态生成实例 | 反射调用与注解解析的关联; 懒加载与即时初始化的差异 |
IOC与后置处理器机制 | 1. 依赖注入通过扫描@Component等注解实现; 2. 后置处理器(如BeanPostProcessor)干预Bean生命周期 | 注解扫描的包路径过滤逻辑; 后置处理器的执行时机 |
Spring整体架构分析 | 1. 先整体后局部的讲解逻辑; 2. 结合流程图解析核心模块(容器、Bean工厂、AOP等) | 架构图中各模块的交互关系 |
5.Spring整体架构分析(2)
知识点 | 核心内容 | 重点 |
Spring容器架构 | IOC容器结构分析,包含bin definition map和单例池设计 | 单例与原型模式的区别,集合存储结构差异 |
Bean定义机制 | 扫描包后生成BeanDefinition对象并存入Map集合 | Bean名称生成规则(类名小写 vs 注解指定) |
单例模式实现 | 非懒加载单例对象预创建并存入单例池 | 单例池(singletonObjects)与原型模式创建时机差异 |
GetBean实现逻辑 | 三阶段处理:不存在检查→单例获取→原型实例化 | 原型模式动态创建与单例缓存机制对比 |
依赖注入机制 | @Autowired注解解析与Bean组装实现 | 循环依赖问题的处理方案 |
扩展机制 | BeanPostProcessor与AOP动态代理的衔接 | 后置处理器调用时机与代理对象生成流程 |
设计模式应用 | 工厂模式(BeanFactory)与策略模式(Scope处理) | 单例模式与原型模式的选择依据 |
6.二说类加载器和classpath
知识点 | 核心内容 | 重点 |
Spring容器实现 | 编写自定义Spring容器,扫描包获取Bean的Class对象 | 扫描包路径配置 vs XML配置文件解析 |
类加载器机制 | Bootstrap/Ext/App三类加载器的默认加载路径差异 | ClassPath动态性(多路径集合) |
类路径解析 | ClassPath包含target/classes等编译输出目录 | 开发目录(src)与运行目录(target)的区分 |
配置方式对比 | 使用Java类(HspSpringConfig)替代beans.xml配置 | DOM4J解析传统XML方式的兼容性 |
包扫描过滤 | 扫描com.hsbedu.spring.component包并排除非Bean类 | 注解识别与类过滤逻辑实现 |
7.编写自己Spring容器 扫描包得到bean(1)
知识点 | 核心内容 | 重点 |
Spring容器开发 | 实现扫描包获取Bean的Class对象 | 注解扫描机制与IOC容器关系 |
自定义注解 | @ComponentScan和@Component注解开发 | Value属性指定扫描包/Bean命名 |
项目结构搭建 | 创建并行子模块hsp-my-spring | Maven模块与语言级别(JDK8)配置 |
代码复用原则 | 复用已有注解实现代码 | 新旧版本功能对比验证 |
组件注册流程 | 通过注解自动注册Bean到IOC容器 | @Controller/@Service等衍生注解处理 |
8.编写自己Spring容器 扫描包得到bean(2)
知识点 | 核心内容 | 重点 |
IOC容器配置类 | 使用hspSpringConfigure类替代beans.xml配置文件,通过@ComponentScan指定扫描包路径 | 配置类与XML的等价性; (需理解注解驱动与XML配置的映射关系) |
组件扫描机制 | 通过@Component注解标记需注入容器的类,支持自定义value命名(未指定时默认类名首字母小写) | 命名优先级规则; (显式value > 默认类名转换) |
依赖注入准备 | 定义MonsterService和MonsterDAO组件,演示后续装配逻辑 | @Component作用域与角色区分; (需区分@Service/@Repository等衍生注解) |
自定义容器实现 | 动态扫描包路径、过滤非@Component类,暂不实例化对象(仅收集Class信息) | 类加载器路径处理; (APPClassLoader获取target/classes路径) |
单例与多例设计 | 预告后续容器将扩展单例池与多例模式处理逻辑 | getBean()方法复杂度升级; (需同时支持两种作用域) |
9.编写自己Spring容器 扫描包得到bean(3)
知识点 | 核心内容 | 重点 |
Spring组件扫描机制 | 通过@Component注解识别Spring Bean,使用类加载器获取target/classes目录下的类文件 | 类路径定位和注解识别逻辑 |
版本兼容性问题处理 | 解决Java Compiler版本不匹配问题(1.5→1.8) | 编译器版本配置与注解支持关系 |
类过滤逻辑实现 | 双重注解检查优化为单次判断,排除非@Component类 | 代码逻辑错位导致的冗余判断 |
调试信息优化 | 简化日志输出格式(类名+Bean状态) | 有效信息提取与输出格式化 |
运行时异常处理 | 预期错误JAVA_COMPILER_ERROR的版本诊断方法 | 错误预判与快速定位技巧 |
类加载路径验证 | 确认扫描范围限定在target/classes目录 | 物理路径与包路径映射关系 |
10.封装BeanDefinition 放入Map(1)
知识点 | 核心内容 | 重点 |
bin信息封装 | 将bin信息封装到bin definition对象中,并存入map管理 | bin名称的确定规则(指定名称或类首字母小写) |
bin作用域处理 | 区分singleton和prototype两种作用域 | prototype类型需反射创建新实例 vs singleton直接从单例池获取 |
bin definition对象属性 | 需包含class对象、作用域标识 | 单例模式需要额外维护单例池集合 |
map结构设计 | key为bin名称,value为bin definition对象 | 未指定名称时自动生成命名规则 |
11.封装BeanDefinition 放入Map(2)
知识点 | 核心内容 | 重点 |
注解scope | 用于指定bean是单例(singleton)还是多实例(prototype) | 单例与多实例的区别:单例全局共享一个实例,多实例每次getBean返回新对象 |
bean定义封装 | 通过BeanDefinition类记录bean的scope和对应class对象 | 关键属性:scope值、class对象(用于反射生成实例) |
注解实现细节 | @Scope注解需设置@Target(TYPE)和@Retention(RUNTIME) | value属性:用于接收singleton/prototype参数值 |
多实例验证 | 在MonsterService类添加@Scope(prototype)进行测试 | 默认情况:未加@Scope注解时默认为单例模式 |
反射机制应用 | 通过存储的Class对象动态生成多实例bean | 核心方法:Class.newInstance()或构造器调用 |
12.封装BeanDefinition 放入Map(3)
知识点 | 核心内容 | 重点 |
Spring容器初始化 | 定义并初始化beanDefinitionMap和singletonObjects集合 | ConcurrentHashMap的使用场景选择 |
Bean定义封装 | 将扫描到的@Component类封装为BeanDefinition对象 | scope默认值(singleton)处理逻辑 |
Bean名称解析 | 通过@Component注解value值或类名首字母小写确定beanName | 未配置value值时的异常处理 |
注解属性提取 | 使用反射获取@Scope注解配置值 | 自定义注解与原生的区分 |
集合类型选择 | ConcurrentHashMap保证线程安全的容器操作 | key-value类型设计(String-Object) |
调试验证 | 通过断点检查map中beanDefinition的正确性 | prototype与singleton的存储验证 |
异常处理 | 未配置scope时的默认值处理 | 空值情况的防御性编程 |
13.封装BeanDefinition 放入Map(4)
知识点 | 核心内容 | 重点 |
Bean命名规则 | 未配置value时默认返回空串,需通过类名首字母小写作为替代方案 | 空串处理逻辑 vs 默认命名规则 |
StringUtils工具类应用 | 使用org.apache.commons.lang包实现首字母小写转换 | 框架依赖冲突(Spring vs Commons) |
JDK版本兼容性问题 | Maven默认JDK1.5导致getDeclaredAnnotation报错 | 临时解决方案(IDE设置) vs 永久方案(POM配置) |
代码重构优化 | 将扫描逻辑抽离为beanDefinitionScan方法 | 构造器臃肿 vs 单一职责原则 |
调试技巧 | 通过断点验证beanDefinitionMap动态数据 | 空值注入风险 vs 命名规范化 |