代理模式与模板方法模式
❓ 面试官:说一下代理模式?静态代理和动态代理有什么区别?【中级】
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论): 代理模式就是在调用者和目标对象之间加一层“中介(代理对象)”。目的是在不修改原目标对象代码的前提下,对它进行功能增强(比如加日志、加事务、加权限校验)。
📝 详细对比实战:
1. 静态代理(比较笨重,基本不用)
- 做法:由程序员手动写一个代理类,实现跟目标类一样的接口。在代理类的方法里调用目标类的方法,并在前后加上自己的增强逻辑。
- 缺点:如果接口有 100 个方法,代理类就得写 100 遍增强逻辑。如果有 10 个不同的接口需要代理,就得写 10 个代理类。太麻烦了。
2. 动态代理(框架的基石,极其重要)
- 做法:代理类不需要手写,而是在程序运行期间,由 JVM 利用反射机制动态生成在内存里的。
- 两大流派(重点必考):
- JDK 动态代理:Java 自带的。它要求目标类必须实现了某个接口。生成的代理类也实现了同样的接口。底层依靠
InvocationHandler和Proxy.newProxyInstance。 - CGLIB 动态代理:第三方库(Spring内置了)。它不要求目标类实现接口,只要不是
final类就行。它的原理是利用 ASM 字节码技术,动态生成一个目标类的子类作为代理。
- JDK 动态代理:Java 自带的。它要求目标类必须实现了某个接口。生成的代理类也实现了同样的接口。底层依靠
- Spring AOP 是用哪种?(连环追问)
- 在 SpringBoot 2.x 以前:如果你的类实现了接口,默认用 JDK;没实现接口,就用 CGLIB。
- 在 SpringBoot 2.x 以后:默认全部使用 CGLIB(因为 CGLIB 性能更好了,且不需要强迫写接口)。
❓ 面试官:你在项目中用过模板方法模式吗?怎么用的?【中级】
频率:🔥🔥🔥🔥
💡 一句话总结(先抛结论): 模板方法模式的核心是:在父类中定义好业务的“骨架流程(模板)”,然后把某些具体的、易变的步骤延迟到子类去实现。
📝 面试高分实战场景:
"面试官您好,在我们公司的文件解析上传模块中,我大量使用了模板方法模式。"
背景痛点:我们要处理别人传过来的 Excel、CSV、TXT 各种格式的财务报表。无论是哪种格式,整体的业务流程都是一模一样的:
- 验证文件签名和格式。
- 解析文件内容(这一步各不相同)。
- 将解析出的数据校验并入库。
- 记录操作日志并发送站内信通知。
用模板方法重构:
- 建一个抽象父类
AbstractFileHandler,在里面写一个process()核心方法。javapublic void process(File file) { verifyFile(file); // 1. 公共方法:直接在父类写死 List<Data> dataList = parseFile(file); // 2. 抽象方法:留给子类去实现 saveToDb(dataList); // 3. 公共方法:父类写死 sendNotify(); // 4. 公共方法:父类写死 } // 延迟给子类的抽象方法 protected abstract List<Data> parseFile(File file); - 将
process()方法打上final关键字:非常重要!这是为了防止子类乱改核心骨架流程。 - 建具体的子类:比如
ExcelFileHandler继承父类,它只需要实现parseFile()方法,用 EasyExcel 去解析就行了。其他的校验、入库逻辑它完全不用管。
- 建一个抽象父类
🌟 为什么这么做(加分项)? 通过模板方法模式,我们把不变的行为固化到了父类中,避免了代码的重复复制;同时把可变的行为留给了子类,极其方便日后的扩展。Spring 源码中的 JdbcTemplate 和 RestTemplate 就是极其典型的模板方法模式应用。