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生命周期管理 |
| 包含 |
应用上下文 |
|
|
依赖注入(DI) |
| 提供 |
SpEL表达式 |
| 支持运行时表达式计算(如 |
AOP动态代理 |
| 实现切面编程(如 |
AspectJ集成 |
| 支持AspectJ注解(需额外依赖AspectJ库)。 |
数据访问与事务
功能点 | 提供模块 | 说明 |
JDBC简化操作 |
| 提供 |
ORM框架集成 |
| 支持Hibernate、JPA、MyBatis(需额外ORM依赖)。 |
声明式事务 |
| 通过 |
JMS消息队列 |
| 集成ActiveMQ、RabbitMQ等(需JMS提供商依赖)。 |
对象-XML映射 |
| 支持JAXB、Castor等XML处理工具。 |
Web开发
功能点 | 提供模块 | 说明 |
Servlet MVC框架 |
| 提供 |
RESTful支持 |
| 底层HTTP协议处理,配合 |
WebSocket通信 |
| 支持实时双向通信(如 |
响应式Web开发 |
| 基于Reactor的非阻塞IO( |
HTTP客户端 |
| 提供 |
测试与集成
功能点 | 提供模块 | 说明 |
集成测试支持 |
| 提供 |
Mock对象 |
| 支持 |
缓存抽象 |
| 集成Ehcache、Redis等(需额外缓存实现)。 |
邮件发送 |
| 提供 |
其他功能
功能点 | 提供模块 | 说明 |
消息协议(STOMP) |
| 用于WebSocket子协议支持。 |
热部署支持 |
| 提供类加载器工具(如Tomcat热部署)。 |
统一日志门面 |
| 自动适配Log4j2、SLF4J等日志框架。 |
生态子项目功能对照
功能点 | 提供子项目 | 说明 |
自动化配置 |
| 通过 |
微服务治理 |
| 提供服务发现(Nacos)、配置中心、网关(Gateway)等。 |
安全控制 |
| 实现认证(OAuth2)、授权( |
批处理任务 |
| 支持分片处理、事务管理( |
分布式会话 |
| 集成Redis实现Session共享。 |
常见问题示例
1、Q:Spring的事务管理由哪个模块实现?
A:
- 核心功能:
spring-tx
模块提供事务抽象接口(如PlatformTransactionManager
)。 - 实际代理:通过
spring-aop
动态代理实现@Transactional
注解。
2、Q:JdbcTemplate
属于哪个模块?
A:spring-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-tx
和spring-jdbc
;- 开发Web应用时,选择
spring-webmvc
或spring-webflux
;- 若需微服务能力,则依赖Spring Cloud的子项目如
spring-cloud-starter-gateway
。”
Spring框架中都用到了哪些设计模式
设计模式 | Spring中的应用 | 解决的问题 |
工厂模式 |
、 | 解耦对象的创建与使用 |
单例模式 | 默认Bean作用域 | 节省资源,共享实例 |
代理模式 | AOP、 | 动态增强功能 |
模板方法模式 |
、 | 封装通用流程 |
观察者模式 |
| 解耦事件发布与监听 |
适配器模式 |
| 统一接口,兼容不同实现 |
装饰器模式 |
| 动态扩展对象功能 |
策略模式 |
| 灵活切换算法 |
责任链模式 |
、AOP拦截器链 | 按顺序处理请求 |
建造者模式 |
| 简化复杂对象的构造 |
面试回答示例: |
“Spring大量使用设计模式来保证灵活性和扩展性,例如:
- 工厂模式(
BeanFactory
管理对象生命周期)、 - 代理模式(AOP实现事务管理)、
- 模板方法模式(
JdbcTemplate
封装数据库操作)、 - 观察者模式(事件驱动编程)。
我在项目中用@Transactional
时,就利用了代理模式动态管理事务边界。”
工厂模式
工厂模式是一种 创建型设计模式,用于 解耦对象的创建与使用。它通过一个统一的接口(工厂)来创建对象,客户端无需关心具体实现类的实例化过程。
核心思想
- 目标:将对象的创建逻辑封装起来,避免直接在代码中写死
new
操作。 - 关键角色:
- 产品接口(Product):定义对象的通用行为(如
Payment
接口)。 - 具体产品(Concrete Product):实现接口的具体类(如
Alipay
、WeChatPay
)。 - 工厂(Factory):负责创建对象的类或方法。
类型 | 简单工厂 | 工厂方法 | 抽象工厂 |
适用场景 | 对象创建逻辑简单 | 需要扩展产品类型 | 需要创建产品族(多个关联产品) |
灵活性 | 低(修改工厂类违反开闭原则) | 高(通过子类扩展) | 最高(支持多维度扩展) |
Spring中的应用 |
的 |
接口 |
|
单例模式
单例模式是一种 创建型设计模式,确保一个类 只有一个实例,并提供 全局访问点。它广泛应用于需要控制资源(如数据库连接池、配置管理)或保证唯一性(如任务管理器)的场景。
核心思想
- 唯一性:一个类只能有一个实例。
- 全局访问:通过静态方法(如
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) 工具类
如Runtime
、Collections.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()
方法
HttpServlet
的service()
方法根据HTTP方法(GET/POST)调用doGet()
或doPost()
,由开发者实现具体逻辑。
(3) 支付流程
(4) 测试框架(如JUnit)
TestCase
定义测试流程(setUp() → testXXX() → tearDown()
),子类填充具体测试逻辑。
模板方法 vs. 策略模式
对比维度 | 模板方法模式 | 策略模式 |
核心思想 | 父类控制流程,子类实现细节 | 通过组合切换完整算法 |
代码复用 | 复用父类算法骨架 | 无复用,策略类独立 |
扩展性 | 通过子类扩展 | 通过新增策略类扩展 |
适用场景 | 算法流程固定,部分步骤可变 | 需要动态切换完整算法 |
举例: |
- 模板方法:支付流程固定(验证→扣款→通知),但支付方式不同。
- 策略模式:排序算法可动态切换(冒泡排序、快速排序)。
优缺点分析
优点 | 缺点 |
1. 代码复用:避免重复流程代码。 | 1. 灵活性受限:算法骨架不可变。 |
2. 扩展性:子类可自由实现细节。 | 2. 类数量增加:每个变体需子类。 |
3. 符合开闭原则:新增子类不影响父类。 |
面试回答示例
问题:模板方法模式在Spring中如何应用的?
回答:
“Spring的JdbcTemplate
是模板方法的经典应用。它固定了JDBC操作流程(如获取连接、执行SQL、释放资源),开发者只需通过RowMapper
或ResultSetExtractor
实现结果处理逻辑。
例如,查询用户时,我们只需关注如何映射结果集,而无需重复写try-catch
资源管理代码。”
关键点:
- 强调 固定流程 + 可变步骤 的设计思想。
- 结合Spring或支付流程等实际案例。
观察者模式
观察者模式是一种 行为型设计模式,用于定义对象间的 一对多依赖关系,当一个对象(被观察者)状态改变时,所有依赖它的对象(观察者)会自动收到通知并更新。它也被称为 发布-订阅模式(Pub-Sub)。
核心思想
- 目标:解耦被观察者(Subject)和观察者(Observer),实现动态的事件通知机制。
- 关键角色:
- Subject(被观察者):维护观察者列表,提供注册/注销方法,并在状态变化时通知观察者。
- Observer(观察者):定义更新接口,接收被观察者的状态变更通知。
- ConcreteSubject/ConcreteObserver:具体实现类。
模式结构
(1) 经典观察者模式
输出:
(2) Java内置的 Observable
和 Observer
(已过时)
Java 9 之前提供了 java.util.Observable
和 java.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 | Redis Pub/Sub、MQTT |
面试回答示例
问题:观察者模式在Spring中如何应用?
回答:
“Spring通过ApplicationEventPublisher
和ApplicationListener
实现观察者模式。例如,订单创建后发布OrderEvent
,库存服务和日志服务监听该事件并异步处理。这种方式解耦了业务逻辑,符合 开闭原则。”
关键点:
- 明确 被观察者(事件发布者)和 观察者(监听器)的角色。
- 结合Spring或GUI事件等实际案例。
适配器模式
适配器模式是一种 结构型设计模式,用于解决 接口不兼容 的问题。它通过一个中间层(适配器)将原本不兼容的类或接口协同工作,类似于现实中的电源适配器(将220V电压转换为设备需要的5V)。
- 目标:让原本因接口不匹配而无法一起工作的类可以协作。
- 关键角色:
- 目标接口(Target):客户端期望的接口(如USB-C)。
- 被适配者(Adaptee):需要被适配的现有类(如老式Micro-USB设备)。
- 适配器(Adapter):实现目标接口,并内部调用被适配者的方法。
实现方式
适配器模式有两种实现方式:
(1) 类适配器(通过继承)
特点:
- 通过继承实现,适配器直接复用被适配者的代码。
- 但Java不支持多继承,若目标接口是类则无法使用。
(2) 对象适配器(通过组合)
特点:
- 通过组合实现,更灵活(可适配多个被适配者)。
- Spring等框架中更常用。
实际应用场景
(1) Spring MVC的HandlerAdapter
- 问题:Spring MVC需要处理多种Controller(如
@Controller
、HttpRequestHandler
),但它们的接口不同。 - 解决:通过不同的
HandlerAdapter
实现类统一适配为ModelAndView
。
(2) JDBC驱动适配
- 不同数据库(MySQL、Oracle)的JDBC驱动通过适配器模式统一成
java.sql.Driver
接口。
(3) 日志框架兼容
- SLF4J作为日志门面,通过适配器兼容Log4j、Logback等具体实现。
适配器模式的优缺点
优点 | 缺点 |
1. 解耦:客户端与被适配者无需直接交互。 | 1. 增加代码复杂度(多了一层调用)。 |
2. 复用性:可复用现有类。 | 2. 过度使用会导致系统混乱。 |
3. 灵活性:适配多个被适配者。 |
与其他模式对比
模式 | 核心区别 |
适配器模式 | 解决接口不兼容问题,事后补救(已有代码无法修改时使用)。 |
装饰器模式 | 增强功能,接口不变(如为 |
代理模式 | 控制访问,接口不变(如延迟加载、权限校验)。 |
面试回答示例
问题:什么是适配器模式?举一个Spring中的例子。
回答:
“适配器模式用于解决接口不兼容问题,比如将Micro-USB转换为USB-C。
在Spring中,HandlerAdapter
是典型应用:DispatcherServlet通过它统一调用不同类型的Controller(如@Controller
和HttpRequestHandler
),无需关心具体实现差异。
我曾在项目中用适配器模式将第三方支付接口(如支付宝、微信)统一成我们系统的支付标准接口。”
关键点:
- 明确适配器的角色(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等实际案例。
策略模式
策略模式是一种 行为型设计模式,它 定义一系列算法,并将每个算法封装成独立的类,使它们可以 互相替换,从而让算法的变化独立于使用它的客户端。
核心思想
- 目标:将 算法 和 使用算法的逻辑 解耦,避免在代码中使用大量的
相关文章:
Java面试(2025)—— Spring
什么是Spring? 结构化回答(总分总模式) ① 一句话定义 “Spring 是一个开源的 Java 企业级应用框架,核心目标是简化企业应用的开发,通过控制反转(IoC)、依赖注入(DI)和面向切面编…...
【C++ Qt】Hello World、初始信号槽、理解对象树 ~~~(通俗易懂 图文并茂)
每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 绪论: 本章是Qt的第二篇,带你认识Qt中几个简单的控件如何实现,以及通过信号槽的方式实现一定的用户和程序的联动,还有许多…...
2025.04.16【GroupedandStackedbarplot】生信数据可视化技法
Negative values This blogpost shows what happens when the dataset includes negative values. Most basic streamchart The most basic streamchart you can build with R and the streamgraph package. 文章目录 Negative valuesMost basic streamchart 2025.04.16【Gro…...
java 设计模式之代理模式
简介 代理模式:使用代理类来增强目标类的功能。在代码结构上,代理对象持有目标对象,通过代理对象访问目标对象,这样可以在不改变目标对象的前提下增加额外的功能,如权限校验、缓存等 代理模式内部的角色:…...
Spring Boot实战:基于策略模式+代理模式手写幂等性注解组件
一、为什么需要幂等性? 核心定义:在分布式系统中,一个操作无论执行一次还是多次,最终结果都保持一致。 典型场景: 用户重复点击提交按钮网络抖动导致的请求重试消息队列的重复消费支付系统的回调通知 不处理幂等的风…...
【.net core】【watercloud】数据库连接报错问题
错误信息: 中文提示 : 连接数据库过程中发生错误,检查服务器是否正常连接字符串是否正确,错误信息:Cannot Open when State is Connecting.DbType"MySql";ConfigId"0". English Message : Connection open …...
69. x 的平方根
目录 一、问题描述 二、解题思路 三、代码 四、复杂度分析 一、问题描述 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意:不允许使用任何内置指数…...
计算机网络基础概论
计算机网络基础概论 目录 一、网络基本概念 1.1. 网络 1.2 互联网 1.3 ip地址 1.3.1 作用 1.3.2 分类 1.4 MAC地址 1.4.1 MAC地址与 IP 地址的关系 1.5 网络协议 二、网络分层模型 2.1 物理层 2.2 数据链路层 2.3 网络层 2.4 传输层 2.5 会话层 2.6 表示层 2.7…...
京东3D空间视频生成技术探索与应用
1. 背景 近年来,随着社交媒体、流媒体平台以及XR设备的快速发展,沉浸式3D空间视频的需求迅猛增长,尤其是在短视频、直播和电影领域,正在重新定义观众的观看体验。2023年,苹果公司发布的空间视频技术为这一趋势注入了新…...
吉利矩阵(DFS)
所有元素为非负整数,且各行各列的元素和都等于 7 的 33 方阵称为 “吉利矩阵”,因为这样的矩阵一共有 666 种。 本题就请你统计一下,各行各列的元素和都等于 5 的 33 方阵一共有多少种? 思路:统计方法数,…...
突破反爬限制的智能数据采集实战 —— 面向中小企业的高效信息监控方案
在当前数据驱动的商业环境中,如何高效、稳定地获取网络数据,已成为众多中小企业进行市场洞察、竞品监测与品牌舆情管理的关键能力。本文将分享一个基于先进API技术构建的社交媒体热点监控系统,聚焦实际应用场景,展示如何在合规前提…...
从0到1:让AI赋能计算机的全流程实践指南
🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:AI 【前言】 在数字化浪潮席卷全球的今天,AI(人工智能)早已不是科幻电影中的虚构概…...
IntelliJ IDEA 2025.1 发布 ,默认 K2 模式 | Android Studio 也将跟进
2025.1 版本已经发布,在此之前我们就聊过该版本的 《Terminal 又发布全新重构版本》,而现在 2025.1 中的 K2 模式也成为了默认选项。 可以预见,这个版本可能会包含不少大坑,为下个 Android Studio 祈祷。 首先有一点可以确定&…...
MCP、A2A、Function Calling:AI架构设计的三驾马车
随着AI浪潮的到来,各种技术和概念也层出不穷,作为技术人应该第一时间掌握其核心概念与原理,以便于在工作和交流中傻傻分不清楚,本文主要就最近大家提及比较多的MCP、A2A和Function Call做下普及与区分 在当今快速发展的AI领域&a…...
NO.96十六届蓝桥杯备战|图论基础-多源最短路|Floyd|Clear And Present Danger|灾后重建|无向图的最小环问题(C++)
多源最短路:即图中每对顶点间的最短路径 floyd算法本质是动态规划,⽤来求任意两个结点之间的最短路,也称插点法。通过不断在两点之间加⼊新的点,来更新最短路。 适⽤于任何图,不管有向⽆向,边权正负&…...
OpenHarmony - 小型系统内核(LiteOS-A)(六)
OpenHarmony - 小型系统内核(LiteOS-A)(六) 七、文件系统 支持的文件系统 FAT 基本概念 FAT文件系统是File Allocation Table(文件配置表)的简称,主要包括DBR区、FAT区、DATA区三个区域。其…...
“星睿O6” AI PC开发套件评测 - Windows on Arm 安装指南和性能测评
引言 Radxa联合此芯科技和安谋科技推出全新的"星睿O6"迷你 ITX 主板。该系统搭载了 CIX P1(CD8180)12 核 Armv9 处理器,拥有高达30T算力的NPU和高性能的GPU,最高配备64GB LPDDR内存,并提供了如 5GbE、HDMI …...
JS实现RSA加密
目录 目标 环境 实现RSA加解密 计算RSA加密允许的最大字节长度 目标 使用JS实现RSA加密解密。计算RSA加密允许的最大字节长度。 环境 node-rsa 实现RSA加解密 const NodeRSA require(node-rsa);function getKey() {const keyLength512// 创建 RSA 密钥对const key new …...
Seata方案详细
Seata(Simple Extensible Autonomous Transaction Architecture)是阿里开源的分布式事务解决方案,支持多种事务模式,提供一站式的事务管理能力。以下是其核心原理、模式及实践的详细解析: 一、Seata核心架构与角色 Se…...
深入了解v-model的原理:v-model拆分为value属性和input事件,表单类组件的封装并用v-model简化代码
文章目录 1.v-model的原理1.1.验证:在input文本输入框中不使用v-model实现双向数据绑定1.2.验证:v-model在下拉菜单中的拆分 2.表单类组件的封装2.1.原理或步骤2.2.示例:表单类组件封装之下拉菜单select的封装 3.使用v-model简化代码完整代码 4.拓展示例:完成input文本输入框的…...
设计模式每日硬核训练 Day 14:组合模式(Composite Pattern)完整讲解与实战应用
🔄 回顾 Day 13:桥接模式小结 在 Day 13 中,我们学习了桥接模式(Bridge Pattern): 用于将“抽象”与“实现”分离,适用于双维度变化场景(如图形类型 渲染方式)。它强调…...
RMSIN论文阅读
自适应旋转卷积 (ARC)是否可以换成可变形卷积 研究背景 指向性遥感图像分割(RRSIS):旨在根据文本描述实现遥感图像中目标对象的像素级定位 像素级定位:像素级定位指的是在图像中对目标对象的每个像素进行准确的定位和标记。这意味…...
【音视频】FLV格式分析
FLV概述 FLV(Flash Video)是Adobe公司推出的⼀种流媒体格式,由于其封装后的⾳视频⽂件体积⼩、封装简单等特点,⾮常适合于互联⽹上使⽤。⽬前主流的视频⽹站基本都⽀持FLV。采⽤FLV格式封装的⽂件后缀为.flv。 FLV封装格式是由⼀个⽂件头(file header)和…...
华为OD机试真题——最小的调整次数/特异性双端队列(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《最小的调…...
华为OD机试真题——统计匹配的二元组个数(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《统计匹配…...
4.16学习总结
完成134. 加油站 - 力扣(LeetCode)算法题 学习了filewriter的相关方法,了解了字符流的底层原理...
java面试篇 4.9
目录 mybatis: 1、mybatis的执行流程 2、mybatis是否支持延迟加载? 当我们需要去开启全局的懒加载时: 3、mybatis的一级和二级缓存 微服务 1、springcloud五大组件有哪些 2、服务注册和发现是什么意思?springcloud如何实现…...
子函数嵌套的意义——以“颜色排序”为例(Python)
多一层缩进精减参数传递,参数少平铺书代码写更佳。 笔记模板由python脚本于2025-04-16 11:52:53创建,本篇笔记适合喜欢子函数嵌套结构代码形式的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值:在于输出思考与经验,而不仅…...
Python深度学习实现验证码识别全攻略
放在前面 Python深度学习实现验证码识别全攻略 Python深度学习实现验证码识别全攻略 在网络安全领域,验证码作为人机区分的关键防线,广泛应用于登录、注册等场景。随着技术演进,验证码样式愈发复杂,传统识别手段力不从心&#…...
【Linux】su、su-、sudo、sudo -i、sudo su - 命令有什么区别?分别适用什么场景?
目录 su su- sudo sudo -i sudo su - /etc/sudoers su 该命令将启动非登录shell,即虽然以该用户身份启动shell,但使用的是原始用户的环境设置。普通用户账户运行 su 命令切换到另一用户账户,需提供要切换的账户的密码。root用户&…...
算法-同余原理
在计算n个数相加或者相乘再取余时,中间结果可能会溢出导致结果错误,这时可以使用同余原理 一、同余原理 ①加法同余 (a[1] a[2] ... a[n])% m > (a[1] % m a[2] % m ... a[n] % m) % m ② 乘法同余 (…...
深入理解卷积神经网络(CNN):从原理到实践
引言 卷积神经网络(Convolutional Neural Networks, CNN)是深度学习领域最具影响力的架构之一,尤其在计算机视觉任务中表现出色。自2012年AlexNet在ImageNet竞赛中一战成名以来,CNN不断演进,推动着图像识别、医疗影像分析、自动驾驶等领域的快…...
深度学习常见模块实现001
文章目录 1.学习目的2.常见模块使用与实现2.1 ResNet18实现2.2 SeNet模块2.3 CBAM模块 1.学习目的 深度学习在图像处理这块,很多模块已经成型,并没有很多新的东西,更多的是不同的模块堆叠,所以需要我们不断总结,动手实…...
Python实现贪吃蛇三
上篇文章Python实现贪吃蛇一,实现了一个贪吃蛇的基础版本。后面第二篇文章Python实现贪吃蛇二修改了一些不足,但最近发现还有两点需要优化: 1、生成食物的时候有概率和记分牌重合 2、游戏缺少暂停功能 先看生成食物的时候有概率和记分牌重合的…...
windows server C# IIS部署
1、添加IIS功能 windows server 2012、windows server 2016、windows server 2019 说明:自带的是.net 4.5 不需要安装.net 3.5 尽量使用 windows server 2019、2016高版本,低版本会出现需要打补丁的问题 2、打开IIS 3、打开iis应用池 .net 4.5 4、添…...
LLM小白自学笔记:1.两种指令微调
一、LoRA 简单来说,LoRA不直接调整个大模型的全部参数(那样太费资源),而是在模型的某些层(通常是注意力层)加个“旁路”——两个小的矩阵(低秩矩阵)。训练时只更新这俩小矩阵&#x…...
杰弗里·辛顿:深度学习教父
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 杰弗里辛顿:当坚持遇见突破,AI迎来新纪元 一、人物简介 杰弗…...
RHCE 第一次作业
一.定义延迟任务 1.安装邮件服务 [roothaiou ~]# yum install s-nail -y 2.配置邮件服务 [roothaiou ~]# vim /etc/mail.rc 3.测试邮件服务 [roothaiou ~]# echo 88888888 | mail -v -s Passion 13571532874163.com 4.设置定时任务 [roothaiou ~]# crontab -e 二.时间同步…...
库洛游戏一面+二面
目录 一面 1. ArrayList和LinkedList的区别,就是我在插入和删除的时候他们在时间复杂度上有什么区别 2. hashmap在java的底层是怎么实现的 3. 红黑树的实现原理 4. 红黑树的特点 5. 为什么红黑树比链表查询速度快 6. 在java中字符串的操作方式有几种 7. Stri…...
基于多模态深度学习的亚急性脊髓联合变性全流程预测与个性化管理技术方案
目录 技术方案文档1. 数据收集与预处理模块2. 多模态预测模型构建3. 术前风险评估系统4. 术中实时监测系统5. 术后并发症预测与护理6. 统计分析与验证模块7. 健康教育系统技术实现说明技术方案文档 1. 数据收集与预处理模块 功能:构建数据管道,清洗并整合多源数据 伪代码示…...
蓝桥杯日期的题型
做题思路 一般分为3个步骤,首先要定义一个结构体来存储月份的天数,第一循环日期,第二判断日期是否为闰年,第三就是题目求什么 结构体 static int[] ds{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 判断是否闰年的函数 public static void f(int m,int d){//被4整…...
【树形dp题解】dfs的巧妙应用
【树形dp题解】dfs的巧妙应用 [P2986 USACO10MAR] Great Cow Gathering G - 洛谷 题目大意: Bessie 正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会。当然,她会选择最方便的地点来举办这次集会。 每个奶牛居住在 N N …...
《AI大模型应知应会100篇》第20篇:大模型伦理准则与监管趋势
第20篇:大模型伦理准则与监管趋势 摘要 随着人工智能(AI)技术的飞速发展,尤其是大模型(如GPT、PaLM等)在自然语言处理、图像生成等领域的广泛应用,AI伦理问题和监管挑战日益凸显。本文将梳理当…...
线上教学平台(vue+springboot+ssm+mysql)含文档+PPT
线上教学平台(vuespringbootssmmysql)含文档PPT 该系统是一个在线教学平台,主要分为管理员和学员两个角色;管理员界面包含首页、交流中心、学员管理、资料类型管理、学习资料管理、交流论坛、我的收藏管理、留言板管理、考试管理…...
Being-0:具有视觉-语言模型和模块化技能的人形机器人智体
25年3月来自北大、北京智源和 BeingBeyond 的论文“Being-0: A Humanoid Robotic Agent with Vision-Language Models and Modular Skills”。 构建能够在现实世界具身任务中达到人类水平表现的自主机器人智体,是人形机器人研究的终极目标。近期,基于基…...
Fiddler 进行断点测试:调试网络请求
目录 一、什么是断点测试? 二、Fiddler 的断点功能 三、如何在 Fiddler 中设置断点? 步骤 1:启动 Fiddler 步骤 2:启用断点 步骤 3:捕获请求 步骤 4:修改请求或响应 四、案例:模拟登录失…...
决策树:ID3,C4.5,CART树总结
树模型总结 决策树部分重点关注分叉的指标,多叉还是单叉,处理离散还是连续值,剪枝方法,以及回归还是分类 一、决策树 ID3(Iterative Dichotomiser 3) 、C4.5、CART决策树 ID3:确定分类规则判别指标、寻找能够最快速降低信息熵的方…...
DDS信号发生器设计
一、基本概述 1.1 DDS简介 DDS信号发生器即直接数字频率合成(Direct Digital Frequency Synthesis,简称DDS)是一种利用数字技术生成信号的方法。它通过数字信号处理技术,将数字信号转换为模拟信号,从而生成高质量的正…...
23黑马产品经理Day01
今天过了一遍23黑马产品经理的基础视频 问题思考维度 抓住核心用户 为什么需要抓住核心用户? 主要原因:用户越来越细分,保持市场竞争力,产品开发推广更聚焦 做产品为什么要了解用户:了解用户的付费点,…...
18-21源码剖析——Mybatis整体架构设计、核心组件调用关系、源码环境搭建
学习视频资料来源:https://www.bilibili.com/video/BV1R14y1W7yS 文章目录 1. 架构设计2. 核心组件及调用关系3. 源码环境搭建3.1 测试类3.2 实体类3.3 核心配置文件3.4 映射配置文件3.5 遇到的问题 1. 架构设计 Mybatis整体架构分为4层: 接口层&#…...