```html
欢迎来到 java spring面试题 专业解析平台 | 域名: www.kaoacca.cn

一、Spring 核心机制深度剖析

⚙️ IOC 控制反转与 DI 依赖注入

在传统的编程模式中,对象A依赖对象B时,通常由A主动去new B()。而 Spring IOC(Inversion of Control)则是将对象的创建权和控制权反转给Spring容器。开发者只需在配置中声明依赖,容器在运行时负责实例化、装配对象。

DI(Dependency Injection) 是 IOC 的具体实现方式。常见的注入方式包括构造器注入、Setter注入和字段注入(@Autowired)。在Spring 官方推荐中,构造器注入因其能确保依赖不可变且支持必填校验,被视为最佳实践。

注入方式 优点 缺点
构造器注入 保证依赖不可变,支持必填检查 参数过多时代码臃肿
Setter注入 可选依赖,灵活性高 无法保证依赖非空
@Autowired字段注入 代码简洁 隐藏依赖,不利于测试

⚡ AOP 面向切面编程实战

AOP(Aspect-Oriented Programming) 旨在将分散在多个类中的公共逻辑(如日志记录、事务管理、权限校验)抽取出来,形成“切面”,从而降低业务代码与系统级服务之间的耦合度。

在 Spring面试题 中,AOP的实现原理是必考题。Spring AOP 默认使用 JDK 动态代理(针对接口)和 CGLIB(针对类)。当Bean实现了接口时,优先使用JDK动态代理;若未实现接口,则使用CGLIB。Spring Boot 2.x 后默认倾向于使用CGLIB。

// 示例:自定义注解实现日志切面
@Aspect
@Component
public class LogAspect {
    @Around("@annotation(com.kaoacca.AuditLog)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature().getName() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

🔄 循环依赖如何解决?

循环依赖是指 Bean A 依赖 Bean B,Bean B 又依赖 Bean A。Spring 通过“三级缓存”机制解决了单例模式下的 setter 注入循环依赖。

1. 一级缓存 singletonObjects:存放完全初始化好的Bean。
2. 二级缓存 earlySingletonObjects:存放原始的Bean对象(尚未填充属性)。
3. 三级缓存 singletonFactories:存放ObjectFactory,用于生成早期引用。

注意:Spring 无法解决构造器注入的循环依赖,因为这需要在Bean实例化之前完成依赖注入,而实例化本身就需要依赖,导致死锁。

二、Spring Boot 自动装配与实战技巧

掌握 Spring Boot 的核心机制,是应对中高级 Java 工程师面试的关键。

《 @EnableAutoConfiguration 源码解析

Spring Boot 的核心在于“约定优于配置”。@EnableAutoConfiguration 通过 @Import(AutoConfigurationImportSelector.class) 导入自动配置类。

其工作流程如下:

  1. 读取 META-INF/spring.factories 文件(Spring Boot 2.7+ 改为 org.springframework.boot.autoconfigure.AutoConfiguration.imports)。
  2. 加载所有候选的自动配置类。
  3. 结合 @ConditionalOnClass、@ConditionalOnMissingBean 等条件注解进行过滤。
  4. 将符合条件的配置类注册到 Spring 容器中。

面试官常问:如何禁用某个自动配置类?答案:spring.autoconfigure.exclude=com.xxx.ExcludeConfig 或在启动类上指定 exclude 属性。

〓 如何手写一个 Starter?〓

在 java spring面试题 中,手写 Starter 是考察开发者对 Spring Boot 机制理解深度的经典题目。只需两步:

1. 创建自动配置模块(starter-autoconfigure):

  • 定义配置属性类(使用 @ConfigurationProperties)。
  • 定义条件化配置类(使用 @Configuration 和 @ConditionalOnProperty)。
  • 在 resources/META-INF/spring.factories 中注册配置类。

2. 创建空接口模块(starter):

  • 仅作为依赖引入,方便用户统一版本管理。
// spring.factories 配置示例
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.kaoacca.myautoconfig.MyAutoConfiguration

『 配置文件加载优先级顺序 『

Spring Boot 允许从多个位置加载配置,优先级从高到低如下:

  1. 命令行参数(如 --server.port=8081)。
  2. Java 系统属性(System.getProperties())。
  3. 操作系统环境变量。
  4. jar 包外部的 application-{profile}.properties/yml。
  5. jar 包内部的 application-{profile}.properties/yml。
  6. jar 包外部的 application.properties/yml。
  7. jar 包内部的 application.properties/yml。
  8. @PropertySource 注解加载的属性。

这种机制使得在 Docker 或 K8s 环境中通过环境变量覆盖配置变得极其简单。

三、Spring Cloud 微服务架构热点

① 服务注册与发现(Nacos/Eureka)

虽然 Eureka 已进入维护模式,但理解其 CAP 定理中的 AP 特性(高可用)仍有价值。目前主流推荐 Nacos,它同时支持 CP 和 AP 模式切换,且集成了配置中心功能,实现了注册中心与配置中心的统一。

② 负载均衡(LoadBalancer)

Spring Cloud LoadBalancer 取代了已停更的 Ribbon。它提供了更轻量的客户端负载均衡方案,支持重试机制和自定义规则。在 Spring面试题 中,常考察其与 Feign 的集成方式。

③ 熔断降级(Sentinel/Resilience4j)

Hystrix 已停止更新,Spring Cloud 官方推荐使用 Resilience4j 或 Alibaba Sentinel。Sentinel 以流量为切入点,提供流量控制、熔断降级、系统负载保护等功能,其核心算法包括滑动窗口和信号量隔离。

④ 网关(Spring Cloud Gateway)

基于 Reactive 模型(WebFlux),性能远超 Zuul 1.x。核心概念包括 Route(路由)、Predicate(断言)和 Filter(过滤器)。面试题常问:如何在 Gateway 中实现全局鉴权?答案:通过自定义 GlobalFilter。

五、深度问答:解决你的最后一公里困惑

Q:Spring 事务失效的常见场景有哪些?

A:这是面试中的“陷阱题”,常见场景包括:

  1. 方法不是 public 修饰。
  2. 异常被 try-catch 吃掉,未向上抛出。
  3. 自身方法调用自身方法(破坏了 AOP 代理)。
  4. 数据库引擎不支持事务(如 MyISAM)。
  5. 传播行为设置为 PROPAGATION_NEVER 或 NOT_SUPPORTED。

Q:如何理解 Spring 的 Bean 生命周期?

A:Bean 生命周期是理解 Spring 扩展点的核心。主要阶段包括:

  • 实例化(Instantiation):通过构造器或工厂方法创建 Bean 实例。
  • 属性填充(Populate):注入依赖属性。
  • 初始化(Initialization):执行 BeanPostProcessor 的前置和后置方法,调用 afterPropertiesSet 或 @PostConstruct 方法。
  • 使用(Usage):Bean 处于就绪状态,可供业务调用。
  • 销毁(Destruction):容器关闭时,执行 destroy 方法或 @PreDestroy。
```
斌知网
蜀ICP备2026017620号-5