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

一、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如何解决?

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

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

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

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

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

@Autowired和@Resource的区别?

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

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

:XML中通过<list><map>标签,或使用@Autowired注入所有匹配类型的Bean。

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

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

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

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

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

如何条件化创建Bean?

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

java 复制代码
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配置<aop:aspectj-autoproxy proxy-target-class="true"/>,或注解@EnableAspectJAutoProxy(proxyTargetClass=true)

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

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

异常 正常 Around前 Before 目标方法 AfterThrowing AfterReturning After Around后

如何定义切点(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)有哪些?

java 复制代码
@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)。
java 复制代码
// 自调用导致事务失效
public void save() {
    this.update(); // 未经过代理类
}
@Transactional
public 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请求处理流程?

@RequestMapping和@GetMapping的区别?

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

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

: 关键类:HandlerMethodArgumentResolver实现类

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

如何返回JSON数据?

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

如何实现文件上传?

java 复制代码
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) {
    file.transferTo(new File("/path/to/save"));
}

如何统一处理异常?

:使用@ControllerAdvice + @ExceptionHandler

java 复制代码
@ControllerAdvice
public 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查询。

如何实现分页查询?

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

实体类状态有哪些?

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

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

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

乐观锁实现

java 复制代码
@Entity
public class Product {
    @Version
    private Long version; // 更新时自动校验版本
}

六、高频难点(10题)

FactoryBean与普通Bean的区别

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

BeanPostProcessor扩展点实战

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

如何动态注册Bean?

:通过BeanDefinitionRegistry编程式注册:

java 复制代码
GenericBeanDefinition beanDef = new GenericBeanDefinition();
beanDef.setBeanClass(MyBean.class);
registry.registerBeanDefinition("myBean", beanDef);

Spring事件机制模型

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

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

java 复制代码
@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

java 复制代码
jdbcClient.sql("SELECT * FROM user WHERE id=?")
.param(1)
.query(User.class);

ProblemDetail 与国际化(i18n)的整合

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

java 复制代码
detail.setDetail(messageSource.getMessage("error.not_found", null, locale));
相关推荐
笨鸟先飞,勤能补拙15 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
城管不管16 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
长和信泰光伏储能16 小时前
京津冀光伏发电:绿色能源的未来之路
python·能源
浦信仿真大讲堂16 小时前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study17 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境18 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境18 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd12318 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy123931021618 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb0019 小时前
一个项目带你入门AI应用开发01
python