> 技术文档 > Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码

Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码


一、Core & IoC容器(19题)

Spring 6 中的 AOT(Ahead-of-Time)编译原理

  1. 编译时机: 在 应用构建阶段(而非运行时)进行分析和预编译。
  2. 输入分析:
    • 扫描应用代码(@Configuration类、@Bean方法等)。
    • 推断Spring应用上下文的结构(Bean定义、依赖关系、配置条件)。
    • 识别运行时必需的动态特性(如代理、反射、资源加载)。
  3. 预生成:
    • 根据分析结果,预先生成 必要的、高效的、可预测的 Java代码(或字节码)。
    • 替代传统Spring在启动时进行的运行时字节码生成(如CGLIB/AOP代理)、类路径扫描、配置解析和Bean定义推导。
  4. 输出: 生成优化的 “应用上下文初始化器”代码,直接构建预解析好的Bean定义,绕过运行时的反射和动态处理。
  5. 目标:
    • 显著减少启动时间: 消除了启动时的动态处理开销。
    • 降低内存占用: 减少运行时代码生成和元数据占用。
    • 原生镜像支持基石: 为使用GraalVM生成轻量级、快速启动的原生可执行文件提供必需的静态分析信息和预生成代码。

总结: Spring AOT 在构建期静态分析应用,预生成高效的初始化代码,替代耗时的运行时动态处理,从而优化启动性能和资源消耗,并为原生编译铺路。

Spring框架的核心功能有哪些?

:IoC(控制反转)和AOP(面向切面编程)。

解释IoC和DI,它们之间的关系是什么?

:IoC是设计思想(控制权反转),DI是实现方式(依赖注入)。Spring通过DI实现IoC。

BeanFactory和ApplicationContext的区别?

:ApplicationContext是BeanFactory的子接口,提供更多企业级功能(如事件发布、国际化等),且默认预加载单例Bean。

特性 BeanFactory ApplicationContext Bean加载方式 懒加载 启动时预加载单例Bean 国际化支持 ❌ ✅ (MessageSource) 事件发布机制 ❌ ✅ (ApplicationEventPublisher) AOP集成 需手动配置 内置支持

Spring Bean的作用域?

  • Singleton(全局单例,无状态服务)
    • 范围:整个IoC容器。
    • 生命周期:容器启动时创建(如果设置为懒加载,则在第一次使用时创建),容器关闭时销毁。
    • 适用场景:无状态的Bean,比如配置类、工具类、服务类等。
  • Prototype(原型)
    • 范围:每次获取时创建新实例。
    • 生命周期:创建后由调用者负责管理,容器不负责销毁。因此,要注意资源释放问题。
    • 适用场景:有状态的Bean,比如每次请求需要独立状态的Bean。
  • Request(请求)
    • 范围:一次HTTP请求。
    • 生命周期:请求开始创建,请求结束销毁。
    • 适用场景:存储请求相关的数据,比如表单数据、请求参数等。
  • Session(会话)
    • 范围:一个用户会话(HTTP Session)。
    • 生命周期:会话创建时创建,会话超时或销毁时销毁。
    • 适用场景:用户会话相关的数据,比如用户登录信息、购物车等。
  • Application(应用)
    • 范围:整个Web应用(ServletContext)。
    • 生命周期:Web应用启动时创建,应用停止时销毁。
    • 与Singleton区别:Singleton是Spring容器级别的单例,而Application是ServletContext级别的单例。在同一个ServletContext中,即使是多个Spring容器(如父子容器)也可能会有多个Application作用域的Bean实例?实际上,通常一个Web应用只有一个Spring容器,所以两者区别不大。但在某些特定场景,比如多个DispatcherServlet,每个DispatcherServlet有自己的容器,但共享同一个ServletContext,此时Application作用域的Bean在ServletContext中是唯一的。
  • WebSocket
    • 范围:一个WebSocket会话。
    • 生命周期:WebSocket会话开始时创建,结束时销毁。
    • 适用场景:WebSocket通信过程中保存状态。

如何配置Bean的作用域?

答:XML中scope属性,或注解@Scope(\"prototype\")

Bean的生命周期详细步骤?

:实例化→属性填充→BeanNameAware→BeanFactoryAware→ApplicationContextAware→BeanPostProcessor前置处理→@PostConstruct→InitializingBean→自定义init方法→BeanPostProcessor后置处理→使用中→@PreDestroy→DisposableBean→自定义destroy方法。

Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码

什么是循环依赖?Spring如何解决?

  • 难点:构造器注入无法解决循环依赖
  • :多个Bean相互引用形成环。Spring通过三级缓存解决(singletonFactories、earlySingletonObjects、singletonObjects),仅支持单例Setter循环依赖:
// 三级缓存结构singletonFactories // 三级:存放Bean工厂(ObjectFactory)earlySingletonObjects // 二级:存放早期引用singletonObjects // 一级:存放完整Bean

三级缓存解决循环依赖流程(Spring 6 优化)

Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码

关键点:三级缓存(singletonFactories)存储 ObjectFactory`,支持 AOP 代理对象的提前创建

构造器循环依赖能否解决?为什么?

:不能。因为构造器注入必须在实例化阶段完成,此时Bean未放入缓存。

@Autowired和@Resource的区别?

  • @Autowired按类型注入,支持@Qualifier指定名称。
  • @Resource(JDK标准注解)默认按名称注入,名称找不到则按类型。

如何注入集合类型(List/Map)?

:XML中通过

标签,或使用@Autowired注入所有匹配类型的Bean。

@Component, @Service, @Controller, @Repository的区别?

:功能相同,均为声明Bean。语义区分:

@Controller:Web层
@Service:业务层
@Repository:数据层(转换持久层异常)
@Component:通用组件

什么是延迟初始化(Lazy Initialization)?

:Bean在首次使用时才创建,而非容器启动时。通过@Lazy(true)配置。

如何条件化创建Bean?

:使用@Conditional注解,实现Condition接口自定义条件。

public class MyCondition implements Condition { public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta) { return ctx.getEnvironment().containsProperty(\"enable.feature\"); }}

FactoryBean和BeanFactory的区别?

  • BeanFactory是IoC容器根接口。
  • FactoryBean是创建复杂对象的工厂Bean,通过getObject()返回实际对象。

如何获取ApplicationContext?

:实现ApplicationContextAware接口或直接注入ApplicationContext

BeanDefinition的作用?

:定义Bean的元数据(类名、作用域、属性等),Spring根据BeanDefinition创建Bean。

PropertySourcesPlaceholderConfigurer的作用?

:解析${}占位符,替换为属性文件中的值。

Spring如何管理父子容器?

:通过HierarchicalBeanFactory接口,子容器可以访问父容器的Bean,但父容器不能访问子容器。


二、AOP(12题)

AOP的核心概念(Aspect, Joinpoint, Pointcut, Advice)?

  • 切面(Aspect):模块化的横切关注点(如日志)。
  • 连接点(Joinpoint):程序执行点(方法调用、异常抛出)。
  • 切点(Pointcut):匹配连接点的表达式。
  • 通知(Advice):在连接点执行的动作(Before/After等)。

Spring AOP和AspectJ的区别?

特性 Spring AOP AspectJ 概念 Spring AOP是Spring框架中的AOP实现,依赖于Spring的容器和其他基础设施 AspectJ是一个独立的AOP框架,不依赖于任何框架或容器 实现 动态代理(JDK/CGLIB) 编译时/加载时织入 性能 运行时开销 无运行时开销 功能 仅支持方法级别 支持字段、构造器等

JDK动态代理和CGLIB代理的区别?

: Spring6仍优先使用 JDK 动态代理(需接口),但 CGLIB 移除了对 ASM 的依赖,改用 ByteBuddy

  • JDK代理:基于接口,使用ProxyInvocationHandler
  • CGLIB:基于继承,生成目标类的子类。

如何强制使用CGLIB代理?

:XML配置,或注解@EnableAspectJAutoProxy(proxyTargetClass=true)

五种通知类型及其执行时机?

  • @Before:方法执行前
  • @After:方法执行后(无论成功或异常)
  • @AfterReturning:方法正常返回后
  • @AfterThrowing:方法抛出异常后
  • @Around:环绕方法执行(可控制是否执行目标方法)

#mermaid-svg-fYPfcaXIzHjjF9YC {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .error-icon{fill:#552222;}#mermaid-svg-fYPfcaXIzHjjF9YC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fYPfcaXIzHjjF9YC .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-fYPfcaXIzHjjF9YC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fYPfcaXIzHjjF9YC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fYPfcaXIzHjjF9YC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fYPfcaXIzHjjF9YC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fYPfcaXIzHjjF9YC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fYPfcaXIzHjjF9YC .marker.cross{stroke:#333333;}#mermaid-svg-fYPfcaXIzHjjF9YC svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fYPfcaXIzHjjF9YC .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .cluster-label text{fill:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .cluster-label span{color:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .label text,#mermaid-svg-fYPfcaXIzHjjF9YC span{fill:#333;color:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .node rect,#mermaid-svg-fYPfcaXIzHjjF9YC .node circle,#mermaid-svg-fYPfcaXIzHjjF9YC .node ellipse,#mermaid-svg-fYPfcaXIzHjjF9YC .node polygon,#mermaid-svg-fYPfcaXIzHjjF9YC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fYPfcaXIzHjjF9YC .node .label{text-align:center;}#mermaid-svg-fYPfcaXIzHjjF9YC .node.clickable{cursor:pointer;}#mermaid-svg-fYPfcaXIzHjjF9YC .arrowheadPath{fill:#333333;}#mermaid-svg-fYPfcaXIzHjjF9YC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fYPfcaXIzHjjF9YC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fYPfcaXIzHjjF9YC .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-fYPfcaXIzHjjF9YC .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-fYPfcaXIzHjjF9YC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fYPfcaXIzHjjF9YC .cluster text{fill:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC .cluster span{color:#333;}#mermaid-svg-fYPfcaXIzHjjF9YC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fYPfcaXIzHjjF9YC :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}异常正常Around前Before目标方法AfterThrowingAfterReturningAfterAround后

如何定义切点(Pointcut)表达式?

:使用AspectJ表达式,如execution(* com.service.*.*(..))

如何在同一切面中控制通知的执行顺序?

:实现Ordered接口或使用@Order注解,值越小优先级越高。

如何获取目标方法的参数?

:在通知方法中使用JoinPoint参数(非环绕)或ProceedingJoinPoint(环绕),调用getArgs()

如何修改目标方法的返回值?

:在@AfterReturning中通过returning属性绑定返回值并修改,或在@Around中修改proceed()的返回值。

如何捕获目标方法抛出的异常?

:在@AfterThrowing中通过throwing属性绑定异常,或在@Around中捕获proceed()的异常。

AOP失效的常见场景

  • 目标类未由Spring管理
  • 方法非public
  • 自调用(this.method())
  • 未通过代理对象调用方法

@AspectJ与Schema-based AOP对比

特性 @AspectJ风格 XML Schema风格 可读性 ✅ (注解直观) ❌ (配置冗长) 编译依赖 ❌ (纯运行时) ❌ 切点表达式 ✅ (强大灵活) ⚠️ (功能受限)

三、事务管理(9题)

Spring事务管理的两种方式?

  • 编程式:TransactionTemplate.execute()
  • 声明式:@Transactional注解

声明式事务实现原理

答:基于AOP + TransactionInterceptor拦截器

@Transactional注解可以作用在哪些位置?

:类(所有public方法)、接口(不推荐)、方法(推荐public方法)。

事务传播行为(Propagation)有哪些?

@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodA() { // 新建独立事务,外层事务挂起}

  • REQUIRED(默认):当前有事务则加入,否则新建。
  • REQUIRES_NEW:新建事务,挂起当前事务。
  • SUPPORTS:有事务则加入,否则非事务运行。
  • NOT_SUPPORTED:非事务运行,挂起当前事务。
  • MANDATORY:必须存在事务,否则抛异常。
  • NEVER:必须不存在事务,否则抛异常。
  • NESTED:嵌套事务(使用保存点)。

事务隔离级别(Isolation)有哪些?

  • DEFAULT:使用数据库默认。
  • READ_UNCOMMITTED:读未提交。
  • READ_COMMITTED:读已提交。
  • REPEATABLE_READ:可重复读。
  • SERIALIZABLE:串行化。
隔离级别 脏读 不可重复读 幻读 READ_UNCOMMITTED ✅ ✅ ✅ READ_COMMITTED ❌ ✅ ✅ REPEATABLE_READ ❌ ❌ ✅ SERIALIZABLE ❌ ❌ ❌

@Transactional失效的常见场景?

  • 方法非public。
  • 自调用(未经过代理)。
  • 异常被捕获未抛出。
  • 异常类型非RuntimeException且未指定rollbackFor
  • 数据库引擎不支持事务(如MyISAM)。
// 自调用导致事务失效public void save() { this.update(); // 未经过代理类}@Transactionalpublic void update() {...}
调用方式 是否经过代理 事务是否生效 外部调用update() ✅ ✅ this.update() ❌ ❌
  • 解决:注入自身代理对象 @Autowired private MyService self;

如何指定回滚的异常类型?

:使用@Transactional(rollbackFor = MyException.class)

事务超时如何设置?

@Transactional(timeout = 5)(单位:秒)。

只读事务的作用?

@Transactional(readOnly=true),优化数据库引擎(如MySQL只读时使用InnoDB只读视图)。


四、Spring MVC(12题)

Spring MVC核心组件及其作用?

  • DispatcherServlet:前端控制器,统一调度。
  • HandlerMapping:映射请求到处理器。
  • HandlerAdapter:执行处理器。
  • ViewResolver:解析视图名到具体视图。
  • HandlerExceptionResolver:处理异常。

DispatcherServlet请求处理流程?

Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码

@RequestMapping和@GetMapping的区别?

  • @GetMapping@RequestMapping(method=RequestMethod.GET)的简写。
  • @RequestMapping底层:RequestMappingHandlerMapping解析注解注册路由

如何获取请求参数?参数绑定原理

: 关键类:HandlerMethodArgumentResolver实现类

  • @RequestParam:获取查询参数。
  • @PathVariable:获取路径参数。
  • @RequestBody:获取请求体(JSON/XML)。
  • HttpServletRequest:原生对象。

如何返回JSON数据?

:使用@RestController@ResponseBody,并添加Jackson依赖。

如何实现文件上传?

@PostMapping(\"/upload\")public String upload(@RequestParam(\"file\") MultipartFile file) { file.transferTo(new File(\"/path/to/save\"));}

如何统一处理异常?

:使用@ControllerAdvice + @ExceptionHandler

@ControllerAdvicepublic class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ModelAndView handleException(Exception ex) { ModelAndView mav = new ModelAndView(\"error\"); mav.addObject(\"msg\", ex.getMessage()); return mav; }}

拦截器(Interceptor) vs 过滤器(Filter)?

  • 过滤器:Servlet规范,处理所有请求。
  • 拦截器:Spring MVC机制,可访问Handler上下文。

如何自定义拦截器?

:实现HandlerInterceptor接口,重写preHandlepostHandleafterCompletion方法,并注册到WebMvcConfigurer

如何实现重定向?

:返回\"redirect:/path\"

如何获取请求头信息?

:使用@RequestHeader(\"User-Agent\") String userAgent

如何实现数据验证?

:使用@Valid注解参数,并配合JSR-303注解(如@NotNull)在实体类上。


五、Spring Data JPA(8题)

JPA和Hibernate的关系?

:JPA是规范,Hibernate是实现。

Spring Data JPA的核心接口?

CrudRepository(基础CRUD)、JpaRepository(扩展分页/排序)。

如何定义查询方法?

:根据方法名自动解析,如findByUsername(String username)

@Query注解的作用?

:自定义JPQL或原生SQL查询。

如何实现分页查询?

Page<User> findAll(Pageable pageable);// 调用:repository.findAll(PageRequest.of(0, 10));

实体类状态有哪些?

:瞬时(Transient)、托管(Managed)、游离(Detached)、删除(Removed)。

Spring 6 源码深度掘金:66+核心原理与高频面试攻坚指南_spring6源码

如何解决N+1查询问题?

  • 使用@EntityGraph指定关联加载策略。
  • JPQL中写JOIN FETCH
@EntityGraph(attributePaths = \"orders\") // 指定立即加载的关联List<User> findAll();

乐观锁实现

@Entitypublic class Product { @Version private Long version; // 更新时自动校验版本}

六、高频难点(10题)

FactoryBean与普通Bean的区别

:FactoryBean返回的是getObject()方法创建的对象,而非自身;FactoryBean 优先初始化,但其生产的 Bean 延迟加载(需通过 & 前缀获取 FactoryBean 本身)

BeanPostProcessor扩展点实战

public class CustomBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String name) { if (bean instanceof MyService) { // 修改Bean实例 } return bean; }}

如何动态注册Bean?

:通过BeanDefinitionRegistry编程式注册:

GenericBeanDefinition beanDef = new GenericBeanDefinition();beanDef.setBeanClass(MyBean.class);registry.registerBeanDefinition(\"myBean\", beanDef);

Spring事件机制模型

  • 三要素
    ApplicationEvent(事件)→ ApplicationListener(监听器)→ ApplicationEventPublisher(发布器)

@Transactional事务传播嵌套场景分析

@Transactional(propagation = Propagation.REQUIRED)public void methodA() { methodB(); // 内嵌事务}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {...}

AOT 编译对 Bean 生命周期的限制?

:AOT 模式下不支持动态代理,需提前生成代理类;BeanPostProcessor 需静态注册。

响应式编程在 Spring 6 的整合

ReactiveAdapterRegistry 支持 Project Reactor/RxJava,与 Spring WebFlux 深度集成。

如何实现 GraalVM 原生镜像支持?

  • 使用 spring-boot-aot-plugin 生成反射配置
  • 排除动态代理类
  • 通过 @NativeHint 定义原生元数据。

Spring 6 中的 JdbcClient 新特性

:简化 JDBC 操作,链式调用代替 JdbcTemplate

jdbcClient.sql(\"SELECT * FROM user WHERE id=?\").param(1).query(User.class);

ProblemDetail 与国际化(i18n)的整合

:通过 MessageSource 动态填充错误消息

detail.setDetail(messageSource.getMessage(\"error.not_found\", null, locale));