知识点:
1.自动装配@Resource(3)
知识点 | 核心内容 | 重点 |
@Autowired与@Resource注入规则 | 默认注入逻辑:未指定参数时,@Resource优先按属性名匹配(by name),失败后按类型匹配(by type);两者均失败则报错 | 名称匹配优先级:属性名需与容器中Bean的ID完全一致 |
多实例场景下的依赖注入 | 容器中存在多个同类型Bean时: - 仅当属性名与某一Bean ID匹配时成功; - 类型匹配必然失败(需唯一性) | 典型错误场景:存在3个UserService实例时,未明确指定名称的注入 |
注解使用规范建议 | 1. 优先使用@Resource; 2. 属性名需符合驼峰命名规范(如userService); 3. 泛型依赖等特殊场景仍需@Autowired | 版本差异:@Autowired未被废弃但官方推荐替换 |
验证实验设计 | 通过修改Bean ID(如userService200)与属性名对比: - 同名匹配成功案例; - 无匹配时的类型检查报错 | 调试技巧:输出Bean哈希值验证注入实例 |
面试高频考点 | 1. 两种注解的匹配顺序差异; 2. 多实例冲突解决方案; 3. 官方推荐注解的演变 | 易错点:认为@Resource会智能合并名称与类型策略 |
2.自动装配小结
知识点 | 核心内容 | 重点 |
自动装配的注意事项 | 当待装配类型在IOC容器中有多个实例时,使用属性名作为ID值进行查找 | 装配失败会抛出异常 |
@Autowired与@Qualifier配合使用 | 通过@Autowired+@Qualifier("指定ID")实现精确装配 | 需要同时使用两个注解 |
@Resource注解使用 | 通过@Resource(name="指定ID")单注解实现装配 | 优先按name匹配,其次按类型 |
装配规则对比 | @Autowired:先类型后名称 @Resource:先名称后类型 | 两种注解的匹配顺序差异 |
最佳实践建议 | 推荐使用@Resource+规范属性名 | 保证命名规范性可避免混淆 |
3.泛型依赖注入(1)
知识点 | 核心内容 | 重点 |
泛型依赖注入 | Spring提供的基于泛型的自动装配机制,通过父类泛型标识实现子类依赖注入 | 泛型类型传递与父类自动装配逻辑的关联性 |
BaseDAO设计模式 | 支持泛型的基类DAO,子类通过继承并指定泛型类型实现具体操作 | 泛型类继承时的类型确定时机(创建对象/继承时) |
BaseService与DAO关联 | 通过泛型依赖注入自动将BookDAO装配到BookService,避免重复声明属性 | 父类泛型参数如何映射到子类依赖关系 |
泛型基础回顾 | 自定义泛型类、泛型类型擦除等Java基础概念 | 泛型类与普通类的实例化差异 |
实际应用场景 | 继承关系复杂的项目(如家居购项目)中简化依赖配置 | 传统装配方式与泛型注入的代码量对比 |
4.泛型依赖注入(2)
知识点 | 核心内容 | 重点 |
泛型依赖注入机制 | 通过泛型传递实现自动装配(如BaseService<T>注入BaseDao<T>子类) | 泛型类型推导与普通@Autowired的区别 |
Spring注解应用 | @Repository标记DAO层、@Service标记业务层 | @Autowired在泛型场景下的强制使用 |
IOC容器调试 | 通过断点查看singletonObjects验证依赖关系 | 动态绑定机制与运行时类型识别 |
分层架构设计 | BaseDao→BookDao/PhoneDao,BaseService→BookService/PhoneService | 抽象类与泛型的联合应用 |
配置文件管理 | 多配置文件拆分(beans06.xml→beans07.xml) | 包扫描路径与注解扫描范围 |
5.AOP文档说明
知识点 | 核心内容 | 重点 |
AOP(切面编程) | 通过动态代理机制实现功能解耦,核心支撑技术包括反射和动态绑定 | 动态代理的实现原理与反射机制的关系 |
动态代理 | 支撑AOP的核心技术,涉及反射和动态绑定 | 动态代理与静态代理的区别及适用场景 |
Spring AOP文档 | 官方文档位置:reference中的aspect oriented programming with spring章节及org.springframework.aop包API | API查找路径与实际开发中的高频使用类 |
学习难点 | 理解底层机制(动态代理、反射)及实际应用场景 | 切面编程的抽象概念与具体代码实现的对应关系 |
6.动态代理需求说明
知识点 | 核心内容 | 重点 |
动态代理 | AOP的核心支撑技术,需通过案例理解其实现逻辑 | 代理模式与原生调用的区别 InvocationHandler接口的作用 |
传统方案实现 | 直接在Car/Ship的run()方法中硬编码"开始/停止"逻辑 | 代码重复问题 违反开闭原则 |
动态代理优势 | 通过代理类统一处理公共逻辑(如"交通工具开始/停止运行") | 反射调用的性能损耗 接口代理的限制 |
案例需求 | 对Vehicle接口的run()方法增强: 1. 统一前置/后置输出 2. 保留子类特有逻辑 | 增强逻辑与业务逻辑的分离 JDK动态代理与CGLIB的区别 |
重点 | 通过对比传统方案与动态代理方案突出解耦价值 | AOP底层原理的关联性 Spring AOP的代理选择策略 |
7.传统方法解决需求
知识点 | 核心内容 | 重点 |
动态代理概念 | 通过接口编程实现方法调用的统一控制,解决代码冗余问题 | 动态绑定机制与接口多态性 |
传统实现方式 | 直接在实现类中硬编码前后置逻辑(Car/Ship类) | 接口引用指向实现类对象的OOP特性 |
代码冗余问题 | 相同的前后置日志出现在所有实现类中 | 维护成本与统一管理难点 |
动态代理优势 | 统一管理方法调用的前后置操作(日志/权限/事务等) | AOP编程思想的实现基础 |
Vehicle接口示例 | 定义run()抽象方法,Car/Ship分别实现 | 编译类型与运行类型的动态绑定 |
开发场景应用 | 权限校验/安全验证/事务管理等横切关注点 | 代理模式与装饰器模式区别 |
教学演示步骤 | 1. 创建接口 2. 编写实现类 3. 暴露冗余问题 4. 引入代理方案 | 测试用例中接口引用的多态应用 |
8.动态代理解决问题(1)
知识点 | 核心内容 | 重点 |
动态代理实现原理 | 通过Proxy.newProxyInstance()生成代理对象,底层基于反射机制 | 接口必须保持不变,代理对象需实现相同接口 |
代理对象创建流程 | 1. 获取类加载器 2. 获取接口信息 3. 实现InvocationHandler处理调用逻辑 | InvocationHandler匿名内部类实现是关键步骤 |
InvocationHandler作用 | 通过invoke()方法拦截目标方法调用,可插入前置/后置逻辑(如日志) | method.invoke(target,args)反射调用原始方法易遗漏 |
反射调用与动态代理关系 | 动态代理通过反射调用目标方法(method.invoke(target,args)) | 需确保目标类实现接口,否则无法代理 |
匿名内部类应用场景 | 快速实现InvocationHandler接口,避免单独创建类文件 | 匿名类中访问外部变量需final修饰(JDK8+隐式支持) |
代理模式优势 | 解耦核心逻辑与横切关注点(如日志、事务) | 动态代理 vs 静态代理(需手动编写代理类) |
9.动态代理解决问题(2)
知识点 | 核心内容 | 重点 |
动态代理(Proxy)实现原理 | 通过Proxy.newProxyInstance创建代理对象,传入目标对象和InvocationHandler,代理对象执行方法时会触发invoke方法 | 编译类型与运行类型的区别:代理对象编译类型仍是接口,但运行类型变为$Proxy0等动态生成的代理类 |
代理对象执行流程 | 调用代理对象方法时,先执行InvocationHandler.invoke,再通过反射调用目标对象方法(如ship.run()) | 易混淆点:直接调用目标对象方法不会触发代理逻辑,必须通过代理对象调用 |
类型判定关键代码 | 通过proxy.getClass()获取代理对象的运行类型,对比编译类型(接口)与运行类型($Proxy0) | 重点验证方法:断点调试观察getClass()结果,结合反射验证方法调用链 |
代理模式应用场景 | 演示通过代理对象增强原始方法(如添加“交通工具开始/停止运行”日志) | 典型场景:日志记录、权限校验、事务管理(AOP底层实现) |
调试技巧 | 通过断点+表达式估算(proxy.getClass())观察运行类型,对比直接调用与代理调用的堆栈差异 | 易错点:未正确传入InvocationHandler或目标对象导致代理失效 |
10.动态代理机制Debug(1)
知识点 | 核心内容 | 重点 |
动态代理机制 | 通过Proxy类创建代理对象,代理对象的运行类型决定方法调用路径 | 运行类型≠编译类型时方法调用路径变化 |
反射调用流程 | 通过Method.invoke()实现方法动态调用,最终执行被代理对象的方法 | invoke参数传递机制(target对象+arguments数组) |
调试技巧 | 使用step into/step over跟踪代理调用链,需关闭"step into"过滤设置 | IDE调试配置差异导致无法进入JDK源码的问题 |
动态绑定验证 | 通过修改被代理对象(Ship→Car)验证运行时的动态绑定效果 | 代理对象不变情况下仅target对象变化即可改变执行逻辑 |
void方法处理 | 无返回值方法执行后result为null的反射特性 | 基本类型返回值与对象返回值的处理差异 |
11.动态代理机制Debug(2)
知识点 | 核心内容 | 重点 |
动态代理机制 | target对象动态变化:传入不同对象执行对应方法 方法动态调用:通过代理对象调用的方法会动态传入 | 代理对象与实际执行对象的映射关系 反射机制在动态代理中的应用 |
方法调用过程 | 包含参数传递、返回值处理的完整调用链演示 关键步骤: 1. 参数类型转换(int→Integer) 2. 方法反射调用 3. 返回值多层传递 | Debug技巧: - 需要两次step into进入核心逻辑 - 参数传递的隐式类型转换 |
动态性体现 | 1. 被代理对象可替换(Car/Ship) 2. 调用方法可扩展(run/fly) 3. 参数动态传递(高度参数) | 代理接口与实现类的松耦合关系 |
调试技巧 | 关键断点: - 方法调用入口 - 参数转换节点 - 返回值传递路径 特殊操作: - step out后需立即step into | Integer.valueOf的自动装箱过程 反射调用时的参数封装 |
框架应用 | MyBatis等框架底层原理: - 动态代理实现接口映射 - 方法拦截与增强 | 动态代理在AOP中的应用场景 |