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

Java Spring框架的核心原理详解

🤟致敬读者

  • 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉

📘博主相关

  • 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息

文章目录

  • Java Spring框架的核心原理详解
    • 一、核心基石:IoC (控制反转) / DI (依赖注入)
    • 二、核心支柱:AOP (面向切面编程)
    • 三、声明式事务管理
    • 四、Spring MVC 核心流程
    • 五、设计模式的应用
    • 六、Bean 的生命周期(重要!)
    • 七、常用扩展点
    • 面试回答建议


📃文章前言

  • 🔷文章均为学习工作中整理的笔记。
  • 🔶如有错误请指正,共同学习进步。

Java Spring框架的核心原理详解

关于 Java 面试中 Spring 框架的核心原理,这是非常高频且重要的考察点。面试官不仅希望你了解基本概念,更期望你深入理解其设计思想、工作机制和关键实现细节。

以下是对 Spring 核心原理的详细解析,涵盖面试中最常被问及的关键点:

一、核心基石:IoC (控制反转) / DI (依赖注入)

  1. 核心思想:

    • 传统方式: 对象自己创建和管理其依赖的对象(new 关键字)。耦合度高,难以测试和扩展。
    • IoC: 控制权反转。 对象的创建、依赖关系的组装不再由对象自身控制,而是交给一个外部容器(Spring IoC 容器)来负责。对象只需声明自己需要什么依赖。
    • DI: 依赖注入。 是 IoC 的一种具体实现方式。容器在创建对象时,自动将其所依赖的对象(或值)“注入”给它(通过构造器、Setter 方法或字段)。
  2. 为什么重要?

    • 解耦: 对象不关心依赖的具体实现和来源,只依赖于接口/抽象。提高了模块化和可维护性。
    • 可测试性: 依赖可以被 Mock 或 Stub,便于单元测试。
    • 可配置性和灵活性: 通过配置文件(XML)或注解(Java Config)就能改变依赖关系或实现类,无需修改代码。
    • 生命周期管理: 容器统一管理对象的创建、初始化、销毁等生命周期。
  3. 关键接口与实现:

    • BeanFactory: 基础 IoC 容器接口。提供基本的 Bean 管理和依赖查找功能。延迟加载(用到时才创建)。
    • ApplicationContext: BeanFactory 的子接口。提供了更丰富的企业级功能,是实际应用中最常用的容器:
      • 继承 BeanFactory 基础的 Bean 管理。
      • 继承 ResourcePatternResolver 资源加载(类路径、文件系统等)。
      • 继承 MessageSource 国际化(i18n)。
      • 继承 ApplicationEventPublisher 事件发布机制。
      • 继承 EnvironmentCapable 环境(Profile、Property)支持。
      • 通常预加载所有单例 Bean: 启动时即创建(可通过配置修改),提高运行时性能。
    • 常见实现类:
      • ClassPathXmlApplicationContext:从类路径加载 XML 配置文件。
      • FileSystemXmlApplicationContext:从文件系统加载 XML 配置文件。
      • AnnotationConfigApplicationContext:基于 Java 配置类(@Configuration)加载 Bean。
      • AnnotationConfigWebApplicationContext:用于 Web 应用的基于注解的上下文。
  4. Bean 的定义与注册:

    • 方式: XML <bean> 标签、@Component 及其衍生注解 (@Service, @Repository, @Controller)、@Bean 注解(在 @Configuration 类中)。
    • 容器启动过程:
      1. 加载配置: 读取 XML 文件或扫描注解标记的类。
      2. 解析配置: 将配置信息解析成 BeanDefinition 对象(包含 Bean 的类名、作用域、是否延迟加载、依赖关系、初始化/销毁方法等元数据)。
      3. 注册 BeanDefinitionBeanDefinition 注册到 BeanDefinitionRegistry(通常是 ApplicationContext 内部实现)。
      4. 实例化 Bean: 根据 BeanDefinition 信息,通过反射机制创建 Bean 实例(调用构造器)。
      5. 填充属性 (DI): 解析 Bean 的依赖(查找或创建依赖的 Bean),并通过反射调用 Setter 方法或直接设置字段值注入依赖。
      6. 初始化: 调用 Bean 的初始化方法(如 @PostConstruct 注解的方法、InitializingBean 接口的 afterPropertiesSet 方法、XML 中配置的 init-method)。
      7. 放入容器: 将初始化完成的 Bean 放入容器(通常是 ConcurrentHashMap)中管理。
      8. 使用: 应用程序通过 getBean() 方法(通常间接通过依赖注入)获取并使用 Bean。
      9. 销毁: 容器关闭时,调用 Bean 的销毁方法(如 @PreDestroy 注解的方法、DisposableBean 接口的 destroy 方法、XML 中配置的 destroy-method)。
  5. 作用域 (Scope):

    • singleton (默认): 容器中只存在一个该 Bean 的实例。
    • prototype 每次请求(getBean() 或注入)都创建一个新的实例。
    • request (Web): 每个 HTTP 请求创建一个实例(仅在 Web 应用中有效)。
    • session (Web): 每个 HTTP Session 创建一个实例(仅在 Web 应用中有效)。
    • application (Web): 每个 ServletContext 生命周期创建一个实例(仅在 Web 应用中有效)。
    • websocket (Web): 每个 WebSocket 会话创建一个实例(仅在 Web 应用中有效)。
  6. 循环依赖:

    • 问题: A 依赖 B,B 又依赖 A。
    • Spring 解决方案 (针对 Singleton Bean):
      • 使用三级缓存 (3-level cache)
        • singletonObjects (一级缓存): 存放完全初始化好的单例 Bean。
        • earlySingletonObjects (二级缓存): 存放提前暴露的(只实例化但未填充属性)Bean 的原始引用代理对象。用于解决循环依赖。
        • singletonFactories (三级缓存): 存放创建 Bean 的工厂对象 (ObjectFactory)。用于在需要时创建 Bean 的早期引用或代理。
      • 解决过程 (以 A->B->A 为例):
        1. 创建 A:实例化 A (此时 A 还不完整),将创建 A 的工厂放入三级缓存。
        2. 为 A 注入属性 B:发现需要 B。
        3. 创建 B:实例化 B (此时 B 也不完整),将创建 B 的工厂放入三级缓存。
        4. 为 B 注入属性 A:去一级缓存找 A(没有) -> 去二级缓存找 A(没有) -> 去三级缓存找到 A 的工厂 -> 调用工厂获取 A 的早期引用(可能是原始对象或代理对象)-> 将这个早期引用放入二级缓存 -> 将这个早期引用注入给 B
        5. B 完成属性注入,执行初始化,成为一个完整的 Bean,放入一级缓存,同时清除二级和三级缓存中关于 B 的信息。
        6. A 成功注入 B(此时 B 已在一级缓存),A 完成属性注入,执行初始化,成为一个完整的 Bean,放入一级缓存,同时清除二级和三级缓存中关于 A 的信息。
      • 关键点: 通过提前暴露一个处于“中间状态”(只实例化,未初始化)的 Bean 引用(原始对象或代理)来解决循环依赖。构造器注入无法解决循环依赖(因为实例化就需要依赖,而这时 Bean 自己都还没创建出来放入缓存)。

二、核心支柱:AOP (面向切面编程)

  1. 核心思想:

    • 将那些与核心业务逻辑无关,但又在多个地方重复出现的功能(如日志、事务、安全、性能监控)横向抽取出来,形成独立的模块(称为“切面” - Aspect)。
    • 在程序运行的特定时机(连接点 - Joinpoint),通过动态代理技术,将切面定义的逻辑(通知 - Advice)“织入”(Weave)到目标对象的方法中,而不修改原有业务代码。
  2. 核心概念:

    • 切面 (Aspect): 封装横切关注点的模块。包含通知和切点。通常是一个用 @Aspect 注解的类。
    • 连接点 (Joinpoint): 程序执行过程中的一个点(如方法调用、方法执行、异常抛出、字段访问)。Spring AOP 只支持方法执行类型的连接点
    • 通知 (Advice): 切面在特定连接点上执行的动作。类型:
      • @Before 在目标方法执行前执行。
      • @AfterReturning 在目标方法成功执行后执行。
      • @AfterThrowing 在目标方法抛出异常后执行。
      • @After / @After(finally) 在目标方法执行完成后执行(无论成功或异常),类似于 finally
      • @Around 环绕通知。功能最强大。可以控制目标方法是否执行、何时执行、修改参数、修改返回值、处理异常等。本质是将目标方法封装在这个通知方法内部执行。
    • 切点 (Pointcut): 一个表达式,用于匹配哪些连接点需要应用通知。@Pointcut 注解定义可重用的切点表达式。
    • 目标对象 (Target Object): 被一个或多个切面通知的对象。包含核心业务逻辑。
    • AOP 代理 (AOP Proxy): Spring AOP 通过创建代理对象来实现切面功能。客户端代码实际调用的是代理对象的方法,代理对象在调用目标方法前后执行通知逻辑。
    • 织入 (Weaving): 将切面应用到目标对象并创建代理对象的过程。Spring AOP 在运行时(通常是应用启动时)通过动态代理完成织入。
  3. 实现机制:动态代理

    • JDK 动态代理 (基于接口):
      • 要求目标对象至少实现一个接口
      • 核心类是 java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler
      • 生成的代理对象实现了目标对象的接口。
    • CGLIB 动态代理 (基于子类):
      • 目标对象可以不实现任何接口
      • 通过生成目标对象的子类作为代理对象。
      • 核心类是 net.sf.cglib.proxy.EnhancerMethodInterceptor
      • 注意: 不能代理 final 类或 final/private/static 方法。
    • Spring 的选择:
      • 默认情况下,如果目标对象实现了接口,则使用 JDK 动态代理。
      • 如果目标对象没有实现接口,则使用 CGLIB 动态代理。
      • 可以通过配置强制使用 CGLIB (<aop:aspectj-autoproxy proxy-target-class="true"/>@EnableAspectJAutoProxy(proxyTargetClass = true))。
  4. @AspectJ 支持:

    • Spring AOP 集成了 AspectJ 的注解切点表达式语言,使得定义切面更加简洁直观。
    • 底层实现仍然是 Spring 自己的运行时动态代理,而非 AspectJ 的编译时/类加载时织入。
  5. 应用场景:

    • 声明式事务管理(Spring 事务的核心实现方式)
    • 日志记录
    • 安全和权限检查
    • 性能监控和统计
    • 异常处理统一封装
    • 缓存管理

三、声明式事务管理

  1. 核心思想:

    • 将复杂的事务管理代码(如 beginTransaction(), commit(), rollback())从业务逻辑中剥离出来。
    • 开发者只需通过注解 (@Transactional) 或 XML 配置声明哪些方法需要事务、事务的传播行为、隔离级别、超时、只读等属性。
    • Spring 通过 AOP 代理在运行时根据声明自动管理事务的边界(开始、提交、回滚)。
  2. 关键接口:

    • PlatformTransactionManager (平台事务管理器): Spring 事务策略的核心接口。不同的数据访问技术(JDBC, JPA, Hibernate, JTA 等)有不同的实现。
      • DataSourceTransactionManager:用于 JDBC 和 MyBatis(基于 DataSource)。
      • HibernateTransactionManager:用于 Hibernate。
      • JpaTransactionManager:用于 JPA。
      • JtaTransactionManager:用于 JTA(分布式事务)。
    • TransactionDefinition 定义事务的属性(传播行为、隔离级别、超时、只读)。
    • TransactionStatus 表示事务的运行时状态(是否新事务、是否回滚、是否完成等)。
  3. 传播行为 (Propagation Behavior): 定义多个事务方法相互调用时,事务应该如何传播。

    • REQUIRED (默认): 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。
    • REQUIRES_NEW 创建一个新事务,如果当前存在事务,则挂起当前事务。新事务独立提交或回滚。
    • SUPPORTS 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
    • NOT_SUPPORTED 以非事务方式执行操作。如果当前存在事务,则挂起当前事务。
    • MANDATORY 必须在事务中运行。如果当前没有事务,则抛出异常。
    • NEVER 必须在非事务方式下运行。如果当前存在事务,则抛出异常。
    • NESTED 如果当前存在事务,则在嵌套事务内执行。嵌套事务可以独立于外层事务回滚。如果当前没有事务,则行为同 REQUIRED注意: 并非所有事务管理器都支持嵌套事务(如 JDBC DataSourceTransactionManager 通过 Savepoint 机制支持)。
  4. 隔离级别 (Isolation Level): 定义事务在访问数据库时,如何与其他并发事务交互。

    • DEFAULT:使用底层数据库默认的隔离级别(通常是 READ_COMMITTED)。
    • READ_UNCOMMITTED:最低级别。可能读到未提交的数据(脏读)。
    • READ_COMMITTED:避免脏读。可能发生不可重复读和幻读。
    • REPEATABLE_READ:避免脏读和不可重复读。可能发生幻读。
    • SERIALIZABLE:最高级别。避免所有并发问题(脏读、不可重复读、幻读)。性能最差。
  5. @Transactional 工作原理:

    1. 使用 @Transactional 注解的方法/类被 Spring AOP 代理。
    2. 当调用代理对象的方法时:
      • 代理从 TransactionManager 获取(或创建)一个事务 (TransactionStatus)。
      • 将事务与当前线程绑定(通常是 ThreadLocal)。
      • 调用目标对象的实际业务方法。
      • 如果方法正常返回,代理提交事务。
      • 如果方法抛出未检查异常(默认 RuntimeExceptionError 的子类)或配置需要回滚的异常,代理回滚事务。
      • 如果抛出已检查异常(默认不回滚),则提交事务(除非配置了 rollbackFor)。
    3. 解除事务与当前线程的绑定。
  6. 常见失效场景:

    • 方法非 public
    • 方法在同一个类内部调用(绕过代理,直接调用目标方法)。
    • 异常被 catch 住且未重新抛出(代理感知不到异常)。
    • 抛出的异常类型不是默认回滚的异常类型且未配置 rollbackFor
    • 使用了错误的事务管理器或未配置事务管理器。
    • 数据库引擎不支持事务(如 MySQL 的 MyISAM)。

四、Spring MVC 核心流程

  1. DispatcherServlet:前端控制器,核心枢纽。
  2. 请求处理流程:
    1. 用户发送请求 -> 到达 DispatcherServlet
    2. DispatcherServlet 调用 HandlerMapping 根据请求 URL 等信息,查找能处理该请求的 Handler (Controller + Method)
    3. DispatcherServlet 调用 HandlerAdapter 找到能执行该 Handler 的适配器(如 RequestMappingHandlerAdapter)。
    4. HandlerAdapter 执行 Handler (Controller 方法):
      • 解析参数(@RequestParam, @PathVariable, @RequestBody, Model 等)。
      • 执行业务逻辑。
      • 返回一个 ModelAndView 对象(包含模型数据 Model 和视图名称 View Name)或直接返回数据(配合 @ResponseBody)。
    5. DispatcherServlet 调用 ViewResolver 根据 Handler 返回的视图名称,解析出具体的 View 对象(如 JSP, Thymeleaf, FreeMarker 模板)。
    6. DispatcherServlet 将模型数据 Model 传递给 View 进行渲染。
    7. View 渲染完成,生成响应内容(HTML, JSON, XML 等)。
    8. DispatcherServlet 将响应返回给用户。

五、设计模式的应用

Spring 框架本身就是设计模式的典范教科书:

  1. 工厂模式 (Factory): BeanFactory, ApplicationContext 是 Bean 创建的工厂。
  2. 单例模式 (Singleton): Spring Bean 默认作用域就是单例。容器保证只创建一个实例。
  3. 代理模式 (Proxy): AOP 的核心实现方式(JDK 动态代理、CGLIB 代理)。
  4. 模板方法模式 (Template Method): JdbcTemplate, RestTemplate, JmsTemplate 等。定义算法骨架,将易变步骤延迟到子类或通过回调实现。
  5. 观察者模式 (Observer / Listener): Spring 事件机制 (ApplicationEvent, ApplicationListener)。
  6. 适配器模式 (Adapter): HandlerAdapter (MVC 中适配不同类型的 Controller 方法执行), AdvisorAdapter (AOP 中适配不同类型的 Advice)。
  7. 策略模式 (Strategy): PlatformTransactionManager (不同事务管理策略), HandlerMapping (不同请求映射策略)。
  8. 装饰器模式 (Decorator): 在 AOP 的 Advice 链中,多个通知对目标方法进行层层包装增强。
  9. 依赖注入模式 (DI): 本身就是 IoC 的核心实现模式。

六、Bean 的生命周期(重要!)

理解 Bean 从创建到销毁过程中经历的各个关键点及其扩展点非常重要:

  1. 实例化 (Instantiate): 调用构造器创建 Bean 实例。
  2. 填充属性 (Populate Properties): 依赖注入(DI),设置属性值。
  3. Bean 后置处理器 (BeanPostProcessor) 前置处理: 调用 postProcessBeforeInitialization 方法。可在此修改 Bean 实例(如返回代理)。
  4. 初始化 (Initialization):
    • 调用 @PostConstruct 注解的方法。
    • 如果实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法。
    • 调用 XML 或 @Bean(initMethod = "...") 指定的自定义初始化方法。
  5. Bean 后置处理器 (BeanPostProcessor) 后置处理: 调用 postProcessAfterInitialization 方法。可在此修改 Bean 实例(如返回代理)。
  6. Bean 可用 (Ready): Bean 完全初始化,可被使用。
  7. 销毁 (Destruction): (容器关闭时)
    • 调用 @PreDestroy 注解的方法。
    • 如果实现了 DisposableBean 接口,调用 destroy() 方法。
    • 调用 XML 或 @Bean(destroyMethod = "...") 指定的自定义销毁方法。

七、常用扩展点

  1. BeanFactoryPostProcessorBeanDefinition 加载之后、Bean 实例化之前,允许修改容器的 BeanDefinition(如修改属性值)。例如: PropertySourcesPlaceholderConfigurer (解析 ${...} 占位符), ConfigurationClassPostProcessor (处理 @Configuration 类)。
  2. BeanPostProcessor 在 Bean 实例化、依赖注入完成之后,在初始化方法调用之前之后,提供修改 Bean 实例的机会(见生命周期第 3、5 步)。例如: AOP 创建代理 (AbstractAutoProxyCreator), AutowiredAnnotationBeanPostProcessor (处理 @Autowired, @Value), CommonAnnotationBeanPostProcessor (处理 @PostConstruct, @PreDestroy, @Resource)。
  3. ApplicationContextAware*Aware 接口: 让 Bean 能感知到 Spring 容器中的特定对象(如 ApplicationContext, BeanFactory, Environment)。实现对应接口,Spring 会在初始化时注入这些对象。慎用,会引入 Spring 耦合。

面试回答建议

  • 结构化: 清晰地分点阐述(如 IoC、AOP、事务、MVC、设计模式)。
  • 深入关键点: 对核心概念(IoC/DI 思想、AOP 原理、事务传播/隔离、Bean 生命周期)要能讲清楚本质和细节(如三级缓存解决循环依赖、动态代理实现 AOP)。
  • 结合实践: 能举例说明这些原理在实际项目中的应用(如用 AOP 做了什么,事务配置遇到过什么问题)。
  • 理解设计模式: 能说出 Spring 中常用的几种设计模式及其体现。
  • 知道限制: 了解 Spring AOP 的局限性(只支持方法级别)、事务失效的常见原因。
  • 表达清晰: 用简洁专业的语言描述,避免过于口语化或啰嗦。

掌握这些核心原理,不仅能让你在 Java 面试中游刃有余地回答 Spring 相关问题,更能深刻理解 Spring 框架的设计之美,提升你的架构思维和开发能力。祝你面试顺利!


📜文末寄语

  • 🟠关注我,获取更多内容。
  • 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
  • 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
  • 🔵​加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
  • 🟣点击下方名片获取更多内容🍭🍭🍭👇

http://www.xdnf.cn/news/14584.html

相关文章:

  • JDK 动态代理: 它的工作原理是什么?它有什么限制?
  • Linux系统基本操作指令
  • 深度实战|星环OS三大创新场景解密:如何用确定性技术重构智能汽车安全与体验?
  • K8s入门指南:架构解析浓缩版与服务间调用实战演示
  • 【51单片机定时中断 工作方式0, 1ms 初值是如何计算的?】2022-5-13
  • vue3 el-table 行颜色根据 字段改变
  • 【论文阅读 | CVPR 2024 |Fusion-Mamba :用于跨模态目标检测】
  • Python打卡训练营Day56
  • 【单调栈】-----【Largest Rectangle in a Histogram】
  • AWS VPC 子网划分实战指南:从基础到进阶
  • 人人都是音乐家?腾讯开源音乐生成大模型SongGeneration
  • 人工智能学习51-ResNet训练
  • 【51单片机2位数码管100毫秒的9.9秒表】2022-5-16
  • 【转】如何画好架构图:架构思维的三大底层逻辑
  • 大数据时代的“广告魔法”:精准投放到底怎么玩?
  • 软件工程概述:核心概念、模型与方法全解析
  • 58-Oracle Autotrace功能和演进
  • Python新春烟花
  • 江科大STM32入门:DMA传输数据
  • CNN工作原理和架构
  • 【基础算法】贪心 (一) :简单贪心
  • Input事件处理引起卡顿
  • vue3+arcgisAPI4案例:智慧林业资源监测分析平台(附源码下载)
  • 55-Oracle-EXPLAIN PLAN(含23ai )实操
  • 终端里的AI黑魔法:OpenCode深度体验与架构揭秘
  • 启动hardhat 项目,下载依赖的npm问题
  • Taro 跨端应用性能优化全攻略:从原理到实践
  • 【设计模式】6.原型模式
  • FTTR+软路由网络拓扑方案
  • NY339NY341美光固态闪存NW841NW843