当前位置: 首页 > news >正文

Java面试(2025)—— Spring

什么是Spring?

结构化回答(总分总模式)

① 一句话定义

“Spring 是一个开源的 Java 企业级应用框架,核心目标是简化企业应用的开发,通过控制反转(IoC)、依赖注入(DI)和面向切面编程(AOP)等机制,提高代码的模块化、可测试性和可维护性。”

② 核心特性(重点展开)

  • IoC 和 DI
    “Spring 的核心是 IoC 容器,它管理对象的生命周期和依赖关系。开发者通过 @Autowired 或 XML 配置声明依赖,由 Spring 自动注入,避免了硬编码的耦合。”
  • 加分点:提到 ApplicationContext 是 Spring 的容器实现,或对比 BeanFactory
  • AOP
    “Spring AOP 通过动态代理实现横切关注点(如事务、日志)的模块化。比如用 @Transactional 注解声明事务,无需在每个方法中重复事务代码。”
  • 加分点:提代理模式(JDK 动态代理 vs. CGLIB)。
  • 模块化设计
    “Spring 是模块化的,开发者可以按需选择功能。比如用 Spring MVC 构建 Web 层,用 Spring Data JPA 操作数据库,用 Spring Security 处理权限。”

③ 实际应用(结合项目)

“我在项目中用 Spring Boot 快速搭建了 RESTful API,通过 @RestController@Service 分层开发,用 Spring Data JPA 简化了数据库操作,并通过 @Aspect 实现了统一的日志切面。”
④ 生态与扩展
“Spring 生态丰富,比如 Spring Boot 的自动配置和内嵌服务器让部署更简单,Spring Cloud 提供了微服务支持(如 Eureka 服务发现、Feign 声明式调用)。”
⑤ 总结优势
“Spring 的优势在于它的轻量级、非侵入性设计,以及强大的社区支持,是现代 Java 企业开发的事实标准。”

面试官可能的追问方向

  • 对比其他框架
    “与传统的 EJB 相比,Spring 更轻量,无需依赖应用服务器,通过 POJO 即可开发。”
  • Spring vs. Spring Boot
    “Spring Boot 是 Spring 的扩展,通过约定优于配置和 Starter 依赖简化了初始配置。”
  • 设计模式的应用
    “Spring 中大量使用工厂模式(BeanFactory)、代理模式(AOP)、模板方法模式(JdbcTemplate)等。”

示例回答(完整版)

“Spring 是一个开源的 Java 企业框架,核心是通过控制反转(IoC)和依赖注入(DI)管理对象依赖,比如用 @Autowired 自动装配 Bean,避免了硬编码的耦合。它还通过 AOP 实现日志、事务等横切关注点的模块化,比如 @Transactional 注解。
我在项目中用 Spring Boot 开发过订单管理系统,通过 Spring Data JPA 操作 MySQL,用 Spring Security 做权限控制。Spring 的模块化设计让我能灵活选择功能,而 Spring Boot 的自动配置(如内嵌 Tomcat)大幅提升了开发效率。
我认为 Spring 的优势在于它的生态成熟,社区活跃,是 Java 企业级开发的首选框架。”

Spring框架的设计目标,设计理念,和核心是什么 ?

设计目标(Why Spring?)

Spring 的诞生是为了解决传统 Java EE 开发(如 EJB)的复杂性,核心目标包括:

  • 简化企业级开发
    通过 POJO(Plain Old Java Object)编程模型,避免侵入式 API(如 EJB 的接口强制实现)。
  • 解耦组件依赖
    用依赖注入(DI)替代硬编码的对象创建(new),提升代码可维护性。
  • 模块化设计
    开发者可以按需选择功能(如 Web、数据访问、安全),而非强制全家桶。
  • 统一技术栈
    整合第三方库(如 Hibernate、MyBatis),提供一致的编程体验。

设计理念(Philosophy)

Spring 的设计遵循几个关键原则:

  • 轻量级与非侵入性
    不强制应用继承或实现 Spring 特定接口(对比 EJB 的 SessionBean)。
  • 面向接口编程
    鼓励通过接口定义行为,依赖注入实现类(符合开闭原则)。
  • 约定优于配置
    通过默认配置减少样板代码(如 Spring Boot 的 application.properties)。
  • 关注点分离
    业务逻辑与基础设施(如事务、日志)通过 AOP 解耦。

核心机制(Core)

Spring 的三大核心技术支柱:

IoC(控制反转)与 DI(依赖注入)

  • IoC 容器
    ApplicationContext 是 Spring 的核心容器,负责创建、组装、管理 Bean 的生命周期。
  • 依赖注入方式
  • 构造器注入(推荐,避免循环依赖):
  • Setter 注入(灵活性高):
  • 字段注入(不推荐,破坏封装性):

AOP(面向切面编程)

  • 动态代理实现
    Spring AOP 通过 JDK 动态代理(接口)或 CGLIB(类)在运行时织入横切逻辑。
  • 典型场景
  • 声明式事务管理(@Transactional
  • 日志记录、性能监控
  • 安全权限检查(如 @PreAuthorize
  • 示例

统一抽象层

  • 模板模式
    封装重复性操作(如 JDBC、事务),开发者只需关注业务逻辑:
  • JdbcTemplate:简化数据库操作,避免手动处理 Connection 和异常。
  • RestTemplate:HTTP 客户端(现已被 WebClient 替代)。
  • 示例

面试回答示例

“Spring 的设计目标是简化企业级 Java 开发,核心是通过 IoC 容器 管理对象依赖(DI),用 AOP 解耦横切关注点,并通过模板模式(如 JdbcTemplate)消除重复代码。
它的设计理念强调 轻量级、模块化,比如用 @Service 标注的普通 Java 类即可成为 Bean,无需继承框架类。我在项目中用 Spring 的 @Transactional 统一管理事务,并通过自定义切面实现了审计日志,这体现了 Spring 对 关注点分离 的支持。”

Spring的优缺点

Spring的核心优点

轻量级与非侵入性

  • POJO编程模型
    开发者无需继承或实现Spring特定接口(对比EJB的SessionBean),保持代码纯净。
  • 低耦合
    通过依赖注入(DI)管理对象依赖,避免硬编码的new操作,便于单元测试和模块替换。

模块化与灵活性

  • 按需引入
    可单独使用核心IoC容器(如ApplicationContext),或结合Spring MVC、Spring Data等模块。
  • 整合第三方库
    提供对Hibernate、MyBatis、Redis等技术的统一支持(如JdbcTemplate简化JDBC操作)。

强大的IoC和AOP支持

  • 依赖注入(DI)
    自动管理Bean生命周期和依赖关系,支持构造器注入(推荐)、Setter注入等。
  • 面向切面编程(AOP)
    通过动态代理实现日志、事务等横切关注点的解耦(如@Transactional声明式事务)。

丰富的生态与社区支持

  • Spring全家桶
  • Spring Boot:约定优于配置,快速构建独立应用。
  • Spring Cloud:微服务解决方案(如服务发现、配置中心)。
  • Spring Security:标准化权限控制。
  • 活跃社区
    长期维护、文档完善,是Java企业开发的事实标准。

提升开发效率

  • 减少样板代码
    自动配置(如Spring Boot的starter)、模板模式(如RestTemplate)减少重复劳动。
  • 快速集成
    内嵌服务器(Tomcat)、自动化依赖管理(Maven/Gradle)简化部署。

Spring的潜在缺点

学习曲线较陡

  • 概念复杂
    IoC、AOP、Bean作用域等概念对新手不友好,需时间理解。
  • 配置方式多样
    XML配置、Java Config、注解混合使用可能导致混乱(早期项目常见)。

运行时性能开销

  • 反射与代理
    AOP和DI依赖反射、动态代理,可能影响性能(但对大多数企业应用可忽略)。
  • 启动时间
    Spring Boot大型应用启动较慢(可通过分层初始化优化)。

过度封装导致调试困难

  • 黑盒问题
    自动化配置(如Spring Boot的auto-configuration)可能掩盖底层细节,排查问题需深入理解机制。
  • 异常信息模糊
    Spring的嵌套异常链可能增加调试难度(如BeanCreationException)。

XML配置的历史包袱

  • 旧项目依赖XML
    早期Spring版本大量使用XML配置,维护成本高(现代项目已转向注解和Java Config)。

灵活性带来的滥用风险

  • AOP滥用
    过度使用切面可能导致代码可读性下降(如业务逻辑分散在切面中)。
  • 依赖注入失控
    大型项目中隐式依赖(@Autowired)可能引发循环依赖或Bean加载顺序问题。

对比其他框架(加分项)

  • vs. Java EE(Jakarta EE)
    Spring更轻量、模块化,而Java EE规范(如EJB)依赖应用服务器,灵活性低。
  • vs. Micronaut/Quarkus
    Spring生态更成熟,但Micronaut/Quarkus启动更快(原生编译支持GraalVM),适合Serverless场景。

面试回答示例

优点
“Spring的核心优势是模块化设计非侵入性,通过IoC和AOP解耦代码,提升可维护性。它的生态完善(如Spring Boot快速开发、Spring Cloud微服务支持),大幅减少企业级应用的样板代码。我在项目中用Spring Security实现RBAC权限控制,用@Transactional简化事务管理,显著提升了开发效率。”

缺点
“Spring的学习曲线较陡,新手需掌握DI、AOP等概念;运行时反射和代理可能带来性能开销,但对大多数应用影响不大。另外,过度依赖自动化配置(如Spring Boot)可能导致问题排查困难,需要熟悉底层机制。”

如何规避缺点?

  • 性能优化
    使用@Lazy延迟加载Bean,避免不必要的AOP拦截。
  • 代码规范
    明确分层(Controller/Service/DAO),限制AOP切面作用域。
  • 调试技巧
    通过--debug模式查看Spring Boot自动配置报告,或自定义ExcludeAutoConfiguration

Spring有哪些应用场景?

场景

推荐Spring子项目

关键优势

传统Web应用

Spring MVC + Thymeleaf

快速开发、内嵌服务器

微服务

Spring Cloud Alibaba

服务治理、分布式配置

高并发实时系统

Spring WebFlux

非阻塞、资源高效

安全敏感型应用

Spring Security

开箱即用的RBAC/OAuth2支持

批处理任务

Spring Batch

事务管理、分片处理

Serverless函数

Spring Cloud Function

原生镜像、快速启动

大数据流处理

Spring Kafka

统一消息模型、Exactly-Once语义

Spring的应用场景非常广泛:

  • 如果是单体应用,可以用Spring MVC快速开发REST API;
  • 如果是微服务架构,Spring Cloud提供了服务注册、配置中心等全套解决方案;
  • 在高并发场景下,WebFlux能通过响应式编程提升吞吐量;
  • 对于安全要求高的系统,Spring Security支持OAuth2和方法级权限控制。

Spring由哪些模块组成?

核心功能(IoC/DI、AOP)

功能点

提供模块

说明

Bean生命周期管理

spring-beans

包含BeanFactory,负责Bean的创建、依赖注入。

应用上下文

spring-context

ApplicationContext扩展BeanFactory,支持事件、国际化等。

依赖注入(DI)

spring-core

提供@Autowired@Resource等注解支持。

SpEL表达式

spring-expression

支持运行时表达式计算(如@Value("#{systemProperties['user.dir']}"))。

AOP动态代理

spring-aop

实现切面编程(如@Before@After)。

AspectJ集成

spring-aspects

支持AspectJ注解(需额外依赖AspectJ库)。

数据访问与事务

功能点

提供模块

说明

JDBC简化操作

spring-jdbc

提供JdbcTemplate,避免手动处理连接和异常。

ORM框架集成

spring-orm

支持Hibernate、JPA、MyBatis(需额外ORM依赖)。

声明式事务

spring-tx

通过@Transactional管理事务(实际由AOP实现)。

JMS消息队列

spring-jms

集成ActiveMQ、RabbitMQ等(需JMS提供商依赖)。

对象-XML映射

spring-oxm

支持JAXB、Castor等XML处理工具。

Web开发

功能点

提供模块

说明

Servlet MVC框架

spring-webmvc

提供DispatcherServlet@Controller@RequestMapping

RESTful支持

spring-web

底层HTTP协议处理,配合spring-webmvc实现REST。

WebSocket通信

spring-websocket

支持实时双向通信(如@MessageMapping)。

响应式Web开发

spring-webflux

基于Reactor的非阻塞IO(Mono/Flux)。

HTTP客户端

spring-web

提供RestTemplate(同步)和WebClient(异步)。

测试与集成

功能点

提供模块

说明

集成测试支持

spring-test

提供@SpringBootTestMockMvc等工具。

Mock对象

spring-test

支持@MockBean模拟依赖。

缓存抽象

spring-context-support

集成Ehcache、Redis等(需额外缓存实现)。

邮件发送

spring-context-support

提供JavaMailSender接口。

其他功能

功能点

提供模块

说明

消息协议(STOMP)

spring-messaging

用于WebSocket子协议支持。

热部署支持

spring-instrument

提供类加载器工具(如Tomcat热部署)。

统一日志门面

spring-jcl

自动适配Log4j2、SLF4J等日志框架。

生态子项目功能对照

功能点

提供子项目

说明

自动化配置

Spring Boot

通过starter依赖简化配置(如spring-boot-starter-web)。

微服务治理

Spring Cloud

提供服务发现(Nacos)、配置中心、网关(Gateway)等。

安全控制

Spring Security

实现认证(OAuth2)、授权(@PreAuthorize)。

批处理任务

Spring Batch

支持分片处理、事务管理(JobStep)。

分布式会话

Spring Session

集成Redis实现Session共享。

常见问题示例

1、Q:Spring的事务管理由哪个模块实现?

A

  • 核心功能spring-tx模块提供事务抽象接口(如PlatformTransactionManager)。
  • 实际代理:通过spring-aop动态代理实现@Transactional注解。

2、Q:JdbcTemplate属于哪个模块?

Aspring-jdbc模块,需显式引入依赖:

3、Q:Spring Boot的自动化配置依赖哪个模块?

A

  • 核心spring-boot-autoconfigure(Spring Boot子项目)。
  • 底层依赖:基于spring-context@Conditional条件装配。

总结

  • 精准定位模块:例如,需要AOP功能时引入spring-aop,而非整个spring-context
  • 避免冗余依赖:根据功能需求选择模块(如纯REST API可不引入spring-webmvc,改用spring-webflux)。
  • 生态整合:复杂场景(如微服务)优先使用Spring Cloud子项目。
    面试回答技巧

“Spring通过模块化设计实现功能解耦。例如:

  • 需要数据库事务时,引入spring-txspring-jdbc
  • 开发Web应用时,选择spring-webmvcspring-webflux
  • 若需微服务能力,则依赖Spring Cloud的子项目如spring-cloud-starter-gateway。”

Spring框架中都用到了哪些设计模式

设计模式

Spring中的应用

解决的问题

工厂模式

BeanFactory

FactoryBean

解耦对象的创建与使用

单例模式

默认Bean作用域

节省资源,共享实例

代理模式

AOP、@Transactional

动态增强功能

模板方法模式

JdbcTemplate

AbstractApplicationContext

封装通用流程

观察者模式

ApplicationEvent

解耦事件发布与监听

适配器模式

HandlerAdapter

统一接口,兼容不同实现

装饰器模式

BeanDefinitionDecorator

动态扩展对象功能

策略模式

PlatformTransactionManager

灵活切换算法

责任链模式

FilterChain

、AOP拦截器链

按顺序处理请求

建造者模式

RestTemplateBuilder

简化复杂对象的构造

面试回答示例



“Spring大量使用设计模式来保证灵活性和扩展性,例如:

  • 工厂模式BeanFactory管理对象生命周期)、
  • 代理模式(AOP实现事务管理)、
  • 模板方法模式JdbcTemplate封装数据库操作)、
  • 观察者模式(事件驱动编程)。
    我在项目中用@Transactional时,就利用了代理模式动态管理事务边界。”

工厂模式

工厂模式是一种 创建型设计模式,用于 解耦对象的创建与使用。它通过一个统一的接口(工厂)来创建对象,客户端无需关心具体实现类的实例化过程。

核心思想

  • 目标:将对象的创建逻辑封装起来,避免直接在代码中写死new操作。
  • 关键角色
  • 产品接口(Product):定义对象的通用行为(如Payment接口)。
  • 具体产品(Concrete Product):实现接口的具体类(如AlipayWeChatPay)。
  • 工厂(Factory):负责创建对象的类或方法。

类型

简单工厂

工厂方法

抽象工厂

适用场景

对象创建逻辑简单

需要扩展产品类型

需要创建产品族(多个关联产品)

灵活性

低(修改工厂类违反开闭原则)

高(通过子类扩展)

最高(支持多维度扩展)

Spring中的应用

BeanFactory

getBean()

FactoryBean

接口

ListableBeanFactory


单例模式

单例模式是一种 创建型设计模式,确保一个类 只有一个实例,并提供 全局访问点。它广泛应用于需要控制资源(如数据库连接池、配置管理)或保证唯一性(如任务管理器)的场景。

核心思想

  • 唯一性:一个类只能有一个实例。
  • 全局访问:通过静态方法(如getInstance())获取该实例。
  • 自行创建:实例由类自身创建,而非外部new

实现方式

(1) 饿汉式(线程安全)

特点:类加载时立即初始化实例,简单但可能浪费资源。


适用场景:实例占用资源少,且程序启动后必定使用。

(2) 懒汉式(线程不安全版)

问题:多线程下可能创建多个实例。

(3) 懒汉式(线程安全版)

解决方式:加synchronized锁,但性能较低。

(4) 双重检查锁(DCL,推荐)

优化:减少锁的粒度,兼顾线程安全与性能。

关键点

  • volatile防止JVM指令重排序导致未初始化完的对象被引用。
  • 两次判空避免多次加锁。

(5) 静态内部类(最优实现)

原理:利用类加载机制保证线程安全,且延迟初始化。

优势

  • 线程安全(JVM保证类加载过程同步)。
  • 懒加载(调用getInstance()时才初始化)。
  • 无锁高性能。

(6) 枚举单例(防反射攻击)

Joshua Bloch在《Effective Java》中推荐的方式

优点

  • 绝对防止反射和序列化破坏单例。
  • 代码简洁,线程安全。

单例模式的破坏与防御

(1) 反射攻击

问题:通过反射调用私有构造方法创建新实例。
防御:在构造方法中抛出异常。


(2) 序列化攻击
问题:反序列化时会生成新对象。
防御:添加readResolve()方法返回已有实例。

实际应用场景

(1) Spring中的单例Bean

  • 默认作用域为singleton,由IoC容器管理唯一实例。
  • 与设计模式的单例区别:Spring的单例是容器级的,而非ClassLoader级。

(2) 工具类

RuntimeCollections.emptyList()等。

(3) 配置管理

单例模式的优缺点

优点

缺点

1. 节省资源:避免重复创建对象。

1. 难以扩展:违背开闭原则。

2. 全局唯一:如数据库连接池。

2. 隐藏依赖:滥用会导致代码耦合。

3. 避免状态混乱:如任务调度。

3. 多线程问题:需额外处理。

面试回答示例

问题:如何实现线程安全的单例模式?
回答
“我通常使用 静态内部类枚举 实现单例,它们天然线程安全且能防御反射攻击。比如在配置管理中,我用静态内部类保证全局唯一配置实例:

若需要延迟加载,会用 双重检查锁(注意volatile防止指令重排序)。”
关键点

  • 掌握至少两种线程安全实现(如静态内部类、DCL)。
  • 了解反射和序列化的防御手段。
  • 结合实际场景(如Spring Bean、工具类)。

代理模式

代理模式是一种 结构型设计模式,通过一个 代理对象 控制对 真实对象 的访问,常用于 延迟初始化访问控制日志记录 等场景。代理模式的核心是 在不修改原始类的情况下增强其功能

核心思想

  • 目标:为其他对象提供一种代理,以控制对这个对象的访问。
  • 关键角色
  • 抽象主题(Subject):定义真实对象和代理对象的公共接口(如UserService)。
  • 真实主题(Real Subject):实际执行业务逻辑的对象(如UserServiceImpl)。
  • 代理(Proxy):持有真实对象的引用,并在调用前后添加额外逻辑(如权限校验、日志记录)。

代理模式的三种实现方式

(1) 静态代理(Static Proxy)

特点:手动编写代理类,编译时确定代理关系。
适用场景:代理逻辑固定,且目标类较少。

输出

缺点:每个目标类都需要一个代理类,代码冗余。

(2) 动态代理(Dynamic Proxy)

特点运行时动态生成代理类,无需手动编写代理类。
实现方式

  • JDK动态代理:基于接口(要求目标类必须实现接口)。
  • CGLIB动态代理:基于继承(可代理无接口的类)。

JDK动态代理示例

输出

优点:一个InvocationHandler可代理多个接口。
缺点:目标类必须实现接口。

CGLIB动态代理示例

输出

优点:可代理无接口的类。
缺点:需引入CGLIB依赖(Spring Core已内置)。

代理模式的应用场景

(1) Spring AOP

  • JDK动态代理:默认对接口的Bean生成代理。
  • CGLIB代理:对无接口的类生成代理(通过proxyTargetClass=true启用)。

(2) MyBatis的Mapper接口

  • MyBatis通过JDK动态代理将Mapper接口转换为数据库操作。

(3) RPC框架(如Dubbo)

  • 远程服务调用时,客户端通过代理透明化网络通信。

(4) 权限控制

代理模式的优缺点

优点

缺点

1. 解耦:客户端与真实对象隔离。

1. 静态代理:类数量爆炸。

2. 增强功能:无侵入式扩展。

2. 动态代理:反射性能开销。

3. 灵活控制:如延迟加载。

面试回答示例

问题:动态代理和静态代理有什么区别?Spring AOP用哪种?
回答
“静态代理需手动编写代理类,适合简单场景;动态代理(JDK/CGLIB)在运行时生成代理类,更灵活。
Spring AOP默认对接口使用 JDK动态代理,对无接口类用 CGLIB(可通过proxyTargetClass=true强制使用CGLIB)。
我在权限系统中用动态代理统一校验接口调用权限,避免在每个方法中重复写if-else。” 关键点

  • 区分静态代理与动态代理的适用场景。
  • 掌握JDK代理和CGLIB的底层原理。
  • 结合Spring AOP或RPC框架等实际案例。

模板方法模式

模板方法模式是一种 行为型设计模式,它定义了一个算法的 骨架(即固定流程),但将某些步骤的 具体实现延迟到子类 中。该模式的核心是 在不改变算法结构的情况下,允许子类重写特定步骤

核心思想

  • 目标:将算法的通用流程固化在父类中,避免重复代码。
  • 关键角色
  • 抽象类(Abstract Class):定义算法的骨架(模板方法)和抽象步骤。
  • 具体子类(Concrete Class):实现父类中定义的抽象步骤。

模式结构

输出结果:

关键概念

(1) 模板方法(Template Method)

  • 定义在抽象类中的 final方法,固定算法流程(如execute())。
  • 调用抽象方法(由子类实现)和具体方法(父类默认实现)。

(2) 抽象步骤

  • 必须由子类实现的抽象方法(如step2())。
  • 例如:支付流程中的「选择支付方式」步骤。

(3) 钩子方法(Hook Method)

  • 非抽象方法,子类 可选择覆盖(如step3())。
  • 用于在算法流程中插入扩展点(如日志记录、权限校验)。

实际应用场景

(1) Spring框架

  • JdbcTemplate:封装了JDBC操作流程(获取连接、执行SQL、释放资源),用户只需实现RowMapper处理结果。

(2) Servlet的service()方法

  • HttpServletservice()方法根据HTTP方法(GET/POST)调用doGet()doPost(),由开发者实现具体逻辑。

(3) 支付流程

(4) 测试框架(如JUnit)

  • TestCase定义测试流程(setUp() → testXXX() → tearDown()),子类填充具体测试逻辑。

模板方法 vs. 策略模式

对比维度

模板方法模式

策略模式

核心思想

父类控制流程,子类实现细节

通过组合切换完整算法

代码复用

复用父类算法骨架

无复用,策略类独立

扩展性

通过子类扩展

通过新增策略类扩展

适用场景

算法流程固定,部分步骤可变

需要动态切换完整算法

举例



  • 模板方法:支付流程固定(验证→扣款→通知),但支付方式不同。
  • 策略模式:排序算法可动态切换(冒泡排序、快速排序)。

优缺点分析

优点

缺点

1. 代码复用:避免重复流程代码。

1. 灵活性受限:算法骨架不可变。

2. 扩展性:子类可自由实现细节。

2. 类数量增加:每个变体需子类。

3. 符合开闭原则:新增子类不影响父类。


面试回答示例

问题:模板方法模式在Spring中如何应用的?
回答
“Spring的JdbcTemplate是模板方法的经典应用。它固定了JDBC操作流程(如获取连接、执行SQL、释放资源),开发者只需通过RowMapperResultSetExtractor实现结果处理逻辑。
例如,查询用户时,我们只需关注如何映射结果集,而无需重复写try-catch资源管理代码。”
关键点

  • 强调 固定流程 + 可变步骤 的设计思想。
  • 结合Spring或支付流程等实际案例。

观察者模式

观察者模式是一种 行为型设计模式,用于定义对象间的 一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)会自动收到通知并更新。它也被称为 发布-订阅模式(Pub-Sub)

核心思想

  • 目标:解耦被观察者(Subject)和观察者(Observer),实现动态的事件通知机制。
  • 关键角色
  • Subject(被观察者):维护观察者列表,提供注册/注销方法,并在状态变化时通知观察者。
  • Observer(观察者):定义更新接口,接收被观察者的状态变更通知。
  • ConcreteSubject/ConcreteObserver:具体实现类。

模式结构

(1) 经典观察者模式

输出

(2) Java内置的 ObservableObserver(已过时)

Java 9 之前提供了 java.util.Observablejava.util.Observer,但因其设计问题(如Observable是类而非接口),现已被废弃,推荐使用 PropertyChangeListener事件总线(如Guava EventBus)。

(3) 基于事件驱动的观察者模式(推荐)

输出

实际应用场景

(1) GUI事件处理(如Java Swing/AWT)

  • Button 是被观察者,ActionListener 是观察者。

(2) Spring事件驱动

  • ApplicationEventPublisher(被观察者)和 ApplicationListener(观察者)。

(3) 消息队列(如Kafka/RabbitMQ)

  • 生产者(被观察者)发布消息,消费者(观察者)订阅并处理。

(4) Vue/React的响应式数据

  • Vue 的 data 是被观察者,视图是观察者,数据变化时自动更新DOM。

观察者模式的优缺点

优点

缺点

1. 解耦:被观察者和观察者独立变化。

1. 内存泄漏:未注销观察者会导致资源占用。

2. 动态订阅:可随时增删观察者。

2. 通知顺序不可控:观察者执行顺序随机。

3. 支持广播通信:一对多通知。

3. 性能问题:观察者过多时通知耗时。

观察者模式 vs. 发布-订阅模式

对比维度

观察者模式

发布-订阅模式

耦合度

被观察者直接持有观察者引用

通过消息代理(Broker)解耦

灵活性

适用于简单场景

适用于分布式系统(如Kafka)

典型实现

Java PropertyChangeSupport

Redis Pub/Sub、MQTT

面试回答示例

问题:观察者模式在Spring中如何应用?
回答
“Spring通过 ApplicationEventPublisherApplicationListener 实现观察者模式。例如,订单创建后发布 OrderEvent,库存服务和日志服务监听该事件并异步处理。这种方式解耦了业务逻辑,符合 开闭原则。”
关键点

  • 明确 被观察者(事件发布者)和 观察者(监听器)的角色。
  • 结合Spring或GUI事件等实际案例。

适配器模式

适配器模式是一种 结构型设计模式,用于解决 接口不兼容 的问题。它通过一个中间层(适配器)将原本不兼容的类或接口协同工作,类似于现实中的电源适配器(将220V电压转换为设备需要的5V)。

  • 目标:让原本因接口不匹配而无法一起工作的类可以协作。
  • 关键角色
  • 目标接口(Target):客户端期望的接口(如USB-C)。
  • 被适配者(Adaptee):需要被适配的现有类(如老式Micro-USB设备)。
  • 适配器(Adapter):实现目标接口,并内部调用被适配者的方法。

实现方式

适配器模式有两种实现方式:

(1) 类适配器(通过继承)

特点

  • 通过继承实现,适配器直接复用被适配者的代码。
  • 但Java不支持多继承,若目标接口是类则无法使用。

(2) 对象适配器(通过组合)

特点

  • 通过组合实现,更灵活(可适配多个被适配者)。
  • Spring等框架中更常用

实际应用场景

(1) Spring MVC的HandlerAdapter

  • 问题:Spring MVC需要处理多种Controller(如@ControllerHttpRequestHandler),但它们的接口不同。
  • 解决:通过不同的HandlerAdapter实现类统一适配为ModelAndView

(2) JDBC驱动适配

  • 不同数据库(MySQL、Oracle)的JDBC驱动通过适配器模式统一成java.sql.Driver接口。

(3) 日志框架兼容

  • SLF4J作为日志门面,通过适配器兼容Log4j、Logback等具体实现。

适配器模式的优缺点

优点

缺点

1. 解耦:客户端与被适配者无需直接交互。

1. 增加代码复杂度(多了一层调用)。

2. 复用性:可复用现有类。

2. 过度使用会导致系统混乱。

3. 灵活性:适配多个被适配者。


与其他模式对比

模式

核心区别

适配器模式

解决接口不兼容问题,事后补救(已有代码无法修改时使用)。

装饰器模式

增强功能,接口不变(如为InputStream添加缓冲功能)。

代理模式

控制访问,接口不变(如延迟加载、权限校验)。


面试回答示例

问题:什么是适配器模式?举一个Spring中的例子。
回答
“适配器模式用于解决接口不兼容问题,比如将Micro-USB转换为USB-C。
在Spring中,HandlerAdapter是典型应用:DispatcherServlet通过它统一调用不同类型的Controller(如@ControllerHttpRequestHandler),无需关心具体实现差异。
我曾在项目中用适配器模式将第三方支付接口(如支付宝、微信)统一成我们系统的支付标准接口。”
关键点

  • 明确适配器的角色(Target/Adaptee/Adapter)。
  • 区分类适配器与对象适配器。
  • 结合实际场景(如框架设计、遗留系统改造)。

装饰器模式

装饰器模式是一种 结构型设计模式,它通过 动态地将责任附加到对象上 来扩展功能,比继承更灵活。核心思想是 在不修改原有类的情况下,通过组合(而非继承)增强对象的功能

核心思想

  • 目标:动态地给对象添加额外的职责,避免继承导致的类爆炸。
  • 关键角色
  • Component(抽象组件):定义核心功能的接口(如InputStream)。
  • ConcreteComponent(具体组件):实现基础功能(如FileInputStream)。
  • Decorator(抽象装饰器):继承/实现Component,并持有Component的引用。
  • ConcreteDecorator(具体装饰器):添加具体增强功能(如BufferedInputStream)。

模式结构

场景:咖啡加料系统

输出

实际应用场景

(1) Java I/O流(经典案例)

  • 组件InputStream(抽象组件)
  • 具体组件FileInputStream(读取文件)
  • 装饰器BufferedInputStream(添加缓冲功能)、DataInputStream(添加数据类型读取)

(2) Java集合框架

  • Collections.unmodifiableList() 返回一个不可修改的装饰器列表。

(3) Spring AOP

  • 通过动态代理(装饰器模式的一种变体)为Bean添加事务、日志等切面功能。

(4) GUI组件

  • 窗口组件(如JScrollPane装饰JTextArea,添加滚动条功能)。

装饰器模式 vs. 继承

对比维度

装饰器模式

继承

灵活性

动态组合功能,运行时扩展

静态扩展,编译时确定

类数量

避免类爆炸(按需组合装饰器)

每增加一种功能需新增子类

代码复用

通过组合复用基础组件功能

通过继承复用父类代码

何时选择装饰器模式?



当需要 动态、透明地扩展对象功能,且不希望因继承导致子类数量激增时。



装饰器模式的优缺点

优点

缺点

1. 开闭原则:无需修改原有代码即可扩展功能。

1. 复杂性:多层装饰时代码可读性降低。

2. 动态组合:运行时灵活添加或移除功能。

2. 设计难度:需正确设计抽象装饰器层。

3. 避免继承缺陷:解决类爆炸问题。


面试回答示例

问题:装饰器模式和继承有什么区别?举一个Java中的例子。
回答
“装饰器模式通过 组合 动态扩展功能,而继承是 静态 的。例如Java的InputStream是抽象组件,FileInputStream是具体组件,BufferedInputStream是装饰器,它为InputStream添加了缓冲功能,而无需通过继承创建BufferedFileInputStream等子类。这种方式更灵活且符合 开闭原则。”
关键点

  • 强调 动态扩展避免类爆炸
  • 结合Java I/O流或Spring AOP等实际案例。

策略模式

策略模式是一种 行为型设计模式,它 定义一系列算法,并将每个算法封装成独立的类,使它们可以 互相替换,从而让算法的变化独立于使用它的客户端。

核心思想

  • 目标:将 算法使用算法的逻辑 解耦,避免在代码中使用大量的
http://www.xdnf.cn/news/3781.html

相关文章:

  • FPGA入门学习Day1——设计一个DDS信号发生器
  • opencv HSV的具体描述
  • 【Java学习笔记】关键字汇总
  • 赛灵思 XCVU440-2FLGA2892E XilinxFPGA Virtex UltraScale
  • ESP32- 开发笔记- 硬件设计-ESP32-C3 天线设计-利用嘉立创EDA来设计
  • 数码管LED显示屏矩阵驱动技术详解
  • Gitignore详解:版本控制中的文件忽略机制
  • 秒杀系统解决两个核心问题的思路方法总结:1.库存超卖问题;2.用户重复抢购问题。
  • Ubuntu 安装WPS Office
  • JavaScript 对象复制:浅拷贝与深拷贝
  • 观察者模式与发布订阅模式:解耦与通信的艺术
  • 【网络】IP层的重要知识
  • 【工具】视频翻译、配音、语音克隆于一体的一站式视频多语言转换工具~
  • Redis面试——事务
  • NoSQL 与 NewSQL 全面对比:如何选择适合你的数据库方案?
  • 使用代理IP提取数据的步骤是什么?代理IP如何提高爬虫采集效率?
  • 2000-2017年各省国有经济煤气生产和供应业固定资产投资数据
  • 从基础概念到前沿应用了解机器学习
  • VFlash的自动化和自定义动作
  • 山东大学软件学院创新项目实训开发日志(15)之中医知识问答历史对话查看bug处理后端信息响应成功但前端未获取到
  • 【模块化拆解与多视角信息6】自我评价:人设构建的黄金50字——从无效堆砌到精准狙击的认知升级
  • 影视产业链中的律师角色以及合规风控要点
  • 【React】项目的搭建
  • B端小程序如何突破常规,成为企业获客新利器?
  • win10下github libiec61850库编译调试sntp_example
  • XCZU4CG‑2SFVC784I 赛灵思 FPGA XilinxZynq UltraScale+ MPSoC
  • JVM详解(曼波脑图版)
  • 【WPF】 自定义控件的自定义属性
  • OpenCV颜色变换cvtColor
  • UE中通过AAIController::MoveTo函数巡逻至目标点后没法正常更新巡逻目标点