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

Spring 面试宝典

目录

  1. Spring 基础概念
  2. IoC 容器
  3. 依赖注入
  4. AOP 面向切面编程
  5. Spring MVC
  6. Spring Boot
  7. Spring Security
  8. Spring Data
  9. Spring Cloud
  10. 事务管理
  11. Bean 生命周期
  12. 高级特性

Spring 基础概念

1. 什么是 Spring 框架?

答案:
Spring 是一个轻量级的开源 Java 框架,用于构建企业级应用程序。它提供了全面的编程和配置模型,支持 Java 应用程序的快速开发。

核心特性:

  • 依赖注入 (DI)
  • 面向切面编程 (AOP)
  • 声明式事务管理
  • MVC 框架
  • 数据访问抽象

2. Spring 框架有哪些核心模块?

答案:

  • Spring Core Container: IoC 容器,Bean 工厂
  • Spring AOP: 面向切面编程
  • Spring Context: 应用上下文
  • Spring DAO: 数据访问对象
  • Spring ORM: 对象关系映射
  • Spring Web: Web 相关功能
  • Spring MVC: 模型-视图-控制器

3. Spring 的优势是什么?

答案:

  • 轻量级: 非侵入性,对应用代码影响小
  • IoC 容器: 管理对象生命周期和依赖关系
  • AOP 支持: 横切关注点的模块化
  • 声明式事务: 简化事务管理
  • 测试友好: 便于单元测试和集成测试
  • 丰富的生态系统: 大量第三方集成

IoC 容器

4. 什么是 IoC(控制反转)?

答案:
IoC (Inversion of Control) 是一种设计原则,将对象的创建和依赖关系的管理从应用程序代码中转移到外部容器。

传统方式:

public class UserService {private UserDao userDao = new UserDaoImpl(); // 硬编码依赖
}

IoC 方式:

public class UserService {private UserDao userDao;public UserService(UserDao userDao) { // 依赖注入this.userDao = userDao;}
}

5. Spring IoC 容器有哪些类型?

答案:

  • BeanFactory: 基础容器接口,延迟加载
  • ApplicationContext: 高级容器,预加载所有单例 Bean

主要实现类:

  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext
  • AnnotationConfigApplicationContext
  • WebApplicationContext

6. BeanFactory 和 ApplicationContext 的区别?

答案:

特性BeanFactoryApplicationContext
Bean 实例化延迟加载预加载单例 Bean
国际化不支持支持
事件发布不支持支持
自动 BeanPostProcessor不支持支持
自动 BeanFactoryPostProcessor不支持支持
性能更快启动启动较慢但功能丰富

依赖注入

7. 什么是依赖注入(DI)?

答案:
依赖注入是 IoC 的一种实现方式,通过外部容器将依赖对象注入到目标对象中。

三种注入方式:

  1. 构造器注入
  2. Setter 注入
  3. 字段注入

8. 构造器注入和 Setter 注入的区别?

答案:

构造器注入:

@Service
public class UserService {private final UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}
}

Setter 注入:

@Service
public class UserService {private UserDao userDao;@Autowiredpublic void setUserDao(UserDao userDao) {this.userDao = userDao;}
}

区别:

  • 构造器注入:强制依赖,不可变,推荐使用
  • Setter 注入:可选依赖,可变,适合可选依赖

9. @Autowired 注解的工作原理?

答案:
@Autowired 是 Spring 的自动装配注解,通过以下方式工作:

  1. 按类型匹配 (byType)
  2. 按名称匹配 (byName)
  3. 构造器注入
  4. 字段注入

匹配优先级:

  1. 按类型找到唯一 Bean
  2. 按类型找到多个 Bean,再按名称匹配
  3. 使用 @Qualifier 指定 Bean 名称
  4. 使用 @Primary 标记主要候选者

AOP 面向切面编程

10. 什么是 AOP?深入理解面向切面编程

答案:

面试2分钟表述:
AOP(面向切面编程)是一种编程范式,核心思想是将横切关注点从业务逻辑中分离出来。

核心概念:

  • 切面:横切关注点的模块化实现,如日志、事务、安全
  • 切点:定义哪些方法需要被拦截
  • 通知:在切点执行的代码,有5种类型:前置、后置、返回、异常、环绕

实际应用:

@Aspect
@Component
public class LoggingAspect {@Around("execution(* com.example.service.*.*(..))")public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();long end = System.currentTimeMillis();System.out.println("方法耗时: " + (end - start) + "ms");return result;}
}

AOP的优势:

  1. 关注点分离:业务逻辑只关注核心功能
  2. 代码复用:一个切面可以应用到多个方法
  3. 易于维护:横切关注点的修改只需要修改切面
  4. 灵活性:可以动态启用/禁用切面

Spring AOP实现:

  • 使用JDK动态代理(基于接口)或CGLIB代理(基于继承)
  • 通过代理对象拦截方法调用,在目标方法执行前后插入切面逻辑

详细技术说明:

AOP 核心思想:
AOP (Aspect-Oriented Programming) 是一种编程范式,用于将横切关注点(Cross-cutting Concerns)从业务逻辑中分离出来,实现关注点的分离和模块化。

为什么需要 AOP?

传统编程的问题:

// 传统方式:业务逻辑和横切关注点混合
public class UserService {public void saveUser(User user) {// 日志记录System.out.println("开始保存用户: " + user.getName());try {// 业务逻辑userRepository.save(user);// 日志记录System.out.println("用户保存成功: " + user.getName());} catch (Exception e) {// 异常处理System.out.println("用户保存失败: " + e.getMessage());throw e;}}public void deleteUser(Long id) {// 重复的日志记录代码System.out.println("开始删除用户: " + id);try {// 业务逻辑userRepository.deleteById(id);// 重复的日志记录代码System.out.println("用户删除成功: " + id);} catch (Exception e) {// 重复的异常处理代码System.out.println("用户删除失败: " + e.getMessage());throw e;}}
}

AOP 解决方案:

// 业务逻辑:只关注核心功能
@Service
public class UserService {public void saveUser(User user) {userRepository.save(user);  // 纯业务逻辑}public void deleteUser(Long id) {userRepository.deleteById(id);  // 纯业务逻辑}
}// 切面:专门处理横切关注点
@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("方法执行前: " + joinPoint.getSignature());}@AfterReturning("execution(* com.example.service.*.*(..))")public void afterReturning(JoinPoint joinPoint) {System.out.println("方法执行成功: " + joinPoint.getSignature());}@AfterThrowing("execution(* com.example.service.*.*(..))")public void afterThrowing(JoinPoint joinPoint, Throwable error) {System.out.println("方法执行失败: " + error.getMessage());}
}

AOP 核心概念详解:

1. 切面 (Aspect)

@Aspect
@Component
public class LoggingAspect {// 切面是横切关注点的模块化实现// 包含多个通知和切点
}

2. 连接点 (Join Point)

// 连接点是程序执行的特定点,如方法调用、异常抛出等
public class UserService {public void saveUser(User user) {  // 这是一个连接点userRepository.save(user);}
}

3. 切点 (Pointcut)

@Aspect
public class LoggingAspect {// 切点是连接点的集合,定义哪些连接点需要被拦截@Pointcut("execution(* com.example.service.*.*(..))")public void serviceMethods() {}@Before("serviceMethods()")public void beforeMethod(JoinPoint joinPoint) {// 通知逻辑}
}

4. 通知 (Advice)

@Aspect
public class LoggingAspect {// 前置通知:在目标方法执行前执行@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("方法执行前");}// 后置通知:在目标方法执行后执行(无论成功还是失败)@After("execution(* com.example.service.*.*(..))")public void afterMethod(JoinPoint joinPoint) {System.out.println("方法执行后");}// 返回通知:在目标方法成功返回后执行@AfterReturning("execution(* com.example.service.*.*(..))")public void afterReturning(JoinPoint joinPoint) {System.out.println("方法执行成功");}// 异常通知:在目标方法抛出异常后执行@AfterThrowing("execution(* com.example.service.*.*(..))")public void afterThrowing(JoinPoint joinPoint, Throwable error) {System.out.println("方法执行失败: " + error.getMessage());}// 环绕通知:包围目标方法,可以控制方法的执行@Around("execution(* com.example.service.*.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("方法执行前");Object result = joinPoint.proceed();  // 执行目标方法System.out.println("方法执行后");return result;}
}

5. 目标对象 (Target)

// 目标对象是被代理的原始对象
@Service
public class UserService {  // 这是目标对象public void saveUser(User user) {userRepository.save(user);}
}

6. 代理 (Proxy)

// 代理是AOP框架创建的对象,用于拦截对目标对象的调用
// Spring会为UserService创建一个代理对象
// 当调用userService.saveUser()时,实际上是调用代理对象的方法

AOP 的优势:

1. 关注点分离

  • 业务逻辑只关注核心功能
  • 横切关注点(日志、事务、安全)独立处理

2. 代码复用

  • 一个切面可以应用到多个类和方法
  • 避免重复代码

3. 易于维护

  • 横切关注点的修改只需要修改切面
  • 业务逻辑和横切关注点独立演化

4. 灵活性

  • 可以通过配置动态启用/禁用切面
  • 支持多种通知类型

实际应用场景:

1. 日志记录

@Aspect
@Component
public class LoggingAspect {@Around("execution(* com.example.service.*.*(..))")public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {long start = System.currentTimeMillis();Object result = joinPoint.proceed();long end = System.currentTimeMillis();System.out.println("方法: " + joinPoint.getSignature() + ", 耗时: " + (end - start) + "ms");return result;}
}

2. 事务管理

@Aspect
@Component
public class TransactionAspect {@Around("@annotation(Transactional)")public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {// 开启事务TransactionManager.begin();try {Object result = joinPoint.proceed();// 提交事务TransactionManager.commit();return result;} catch (Exception e) {// 回滚事务TransactionManager.rollback();throw e;}}
}

3. 权限控制

@Aspect
@Component
public class SecurityAspect {@Before("@annotation(RequirePermission)")public void checkPermission(JoinPoint joinPoint) {RequirePermission annotation = getAnnotation(joinPoint);if (!hasPermission(annotation.value())) {throw new SecurityException("权限不足");}}
}

AOP 的局限性:

  • 只能拦截public方法
  • 不能拦截final方法
  • 不能拦截static方法
  • 同类内部调用不会触发切面

11. Spring AOP 的通知类型有哪些?

答案:

  1. @Before: 前置通知
  2. @After: 后置通知
  3. @AfterReturning: 返回通知
  4. @AfterThrowing: 异常通知
  5. @Around: 环绕通知

示例:

@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("方法执行前: " + joinPoint.getSignature());}@Around("execution(* com.example.service.*.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("方法执行前");Object result = joinPoint.proceed();System.out.println("方法执行后");return result;}
}

12. Spring AOP 的代理机制详解?

答案:

Spring AOP 使用两种代理机制来实现面向切面编程:

JDK 动态代理:

原理:基于接口的代理,运行时动态生成代理类

// 目标接口
public interface UserService {void saveUser(User user);void deleteUser(Long id);
}// 目标类
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(User user) {System.out.println("保存用户: " + user.getName());}@Overridepublic void deleteUser(Long id) {System.out.println("删除用户: " + id);}
}// JDK动态代理实现
public class JdkProxyExample {public static void main(String[] args) {UserService target = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),    // 类加载器target.getClass().getInterfaces(),     // 接口数组new InvocationHandler() {              // 调用处理器@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行前: " + method.getName());Object result = method.invoke(target, args);System.out.println("方法执行后: " + method.getName());return result;}});proxy.saveUser(new User("张三"));}
}

CGLIB 代理:

原理:基于继承的代理,运行时生成目标类的子类

// 目标类(不需要实现接口)
public class UserService {public void saveUser(User user) {System.out.println("保存用户: " + user.getName());}public void deleteUser(Long id) {System.out.println("删除用户: " + id);}
}// CGLIB代理实现
public class CglibProxyExample {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);  // 设置父类enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("方法执行前: " + method.getName());Object result = proxy.invokeSuper(obj, args);  // 调用父类方法System.out.println("方法执行后: " + method.getName());return result;}});UserService proxy = (UserService) enhancer.create();proxy.saveUser(new User("李四"));}
}

两种代理的详细对比:

特性JDK动态代理CGLIB代理
实现方式基于接口基于继承
目标要求必须实现接口不需要接口
代理对象实现相同接口继承目标类
方法调用通过反射调用直接调用父类方法
性能反射调用较慢直接调用较快
限制只能代理接口方法不能代理final方法
依赖JDK自带需要CGLIB库

Spring中的选择规则:

// Spring配置
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)  // 强制使用CGLIB
public class AopConfig {// ...
}// 或者通过XML配置
<aop:aspectj-autoproxy proxy-target-class="true"/>

实际应用示例:

// 有接口的情况 - 使用JDK动态代理
@Service
public class UserServiceImpl implements UserService {@Overridepublic void saveUser(User user) {// 业务逻辑}
}// 无接口的情况 - 使用CGLIB代理
@Service
public class UserService {public void saveUser(User user) {// 业务逻辑}
}// 切面类
@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("方法执行前: " + joinPoint.getSignature());}
}

性能对比:

// JDK动态代理性能测试
public class ProxyPerformanceTest {public static void main(String[] args) {// JDK动态代理long start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {// 调用代理方法}long jdkTime = System.currentTimeMillis() - start;// CGLIB代理start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {// 调用代理方法}long cglibTime = System.currentTimeMillis() - start;System.out.println("JDK代理耗时: " + jdkTime + "ms");System.out.println("CGLIB代理耗时: " + cglibTime + "ms");}
}

选择建议:

  • 有接口:优先使用JDK动态代理,符合面向接口编程
  • 无接口:使用CGLIB代理,性能更好
  • 性能敏感:考虑使用CGLIB代理
  • 需要代理final方法:只能使用JDK动态代理(但final方法本身不能被代理)

Spring MVC

13. Spring MVC 的工作流程?

答案:

  1. 用户请求 → DispatcherServlet
  2. DispatcherServlet → HandlerMapping 查找处理器
  3. HandlerMapping → 返回 HandlerExecutionChain
  4. DispatcherServlet → HandlerAdapter 调用处理器
  5. HandlerAdapter → 调用 Controller 方法
  6. Controller → 返回 ModelAndView
  7. DispatcherServlet → ViewResolver 解析视图
  8. ViewResolver → 返回 View 对象
  9. DispatcherServlet → 渲染视图
  10. 响应 → 返回给用户

14. @Controller 和 @RestController 的区别?

答案:

@Controller:

  • 返回视图名称
  • 需要配合 @ResponseBody 返回 JSON
  • 用于传统 Web 应用

@RestController:

  • 组合注解:@Controller + @ResponseBody
  • 直接返回数据(JSON/XML)
  • 用于 RESTful API

示例:

@Controller
public class UserController {@RequestMapping("/user")public String getUser() {return "user"; // 返回视图名称}@RequestMapping("/user/json")@ResponseBodypublic User getUserJson() {return new User(); // 返回 JSON}
}@RestController
public class UserRestController {@RequestMapping("/user")public User getUser() {return new User(); // 直接返回 JSON}
}

15. Spring MVC 的常用注解?

答案:

请求映射:

  • @RequestMapping: 通用请求映射
  • @GetMapping: GET 请求映射
  • @PostMapping: POST 请求映射
  • @PutMapping: PUT 请求映射
  • @DeleteMapping: DELETE 请求映射

参数绑定:

  • @RequestParam: 绑定请求参数
  • @PathVariable: 绑定路径变量
  • @RequestBody: 绑定请求体
  • @ModelAttribute: 绑定模型属性

示例:

@RestController
@RequestMapping("/api/users")
public class UserController {@GetMapping("/{id}")public User getUser(@PathVariable Long id) {return userService.findById(id);}@PostMappingpublic User createUser(@RequestBody User user) {return userService.save(user);}@GetMappingpublic List<User> getUsers(@RequestParam(defaultValue = "0") int page) {return userService.findAll(page);}
}

Spring Boot

16. 什么是 Spring Boot?

答案:
Spring Boot 是基于 Spring 框架的快速开发脚手架,简化了 Spring 应用的配置和部署。

核心特性:

  • 自动配置: 根据依赖自动配置 Bean
  • 起步依赖: 预定义的依赖组合
  • 内嵌服务器: 无需外部容器
  • 生产就绪: 监控、健康检查等特性

17. @SpringBootApplication 组合注解详解?

答案:

@SpringBootApplication 是一个组合注解,包含三个核心注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration  // 1. 配置类标识
@EnableAutoConfiguration  // 2. 启用自动配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {// ...
}

三个核心注解的作用:

  1. @SpringBootConfiguration

    • 等价于 @Configuration
    • 标识这是一个配置类
    • 允许在上下文中注册额外的Bean
  2. @EnableAutoConfiguration

    • 启用Spring Boot的自动配置机制
    • 根据类路径依赖自动配置Bean
    • 核心功能:自动配置
  3. @ComponentScan

    • 启用组件扫描
    • 扫描当前包及子包下的组件
    • 自动注册 @Component@Service@Repository 等注解的类

等价写法:

// 使用组合注解
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}// 等价于分别使用三个注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

18. Spring Boot 启动与自动装配完整流程(源码级深度解析)

答案: Spring Boot 启动时的自动装配是整个框架的核心机制,通过一系列精妙的设计实现了"约定优于配置"。

重要说明:以下源码是基于 Spring Boot 2.x/3.x 真实源码简化而来,保留核心逻辑,去除了异常处理、日志、部分参数校验等非核心代码,便于面试理解和讲解。实际源码会更复杂,包含更多的边界处理和优化。

Spring Boot启动时的自动装配流程分为5个阶段:首先,SpringApplication.run()启动容器,创建ApplicationContext。第二,通过@SpringBootApplication中的@EnableAutoConfiguration触发自动配置。第三,AutoConfigurationImportSelector从META-INF/spring.factories加载所有候选配置类。第四,通过@Conditional系列注解过滤,只保留满足条件的配置类。第五,Spring容器解析配置类,创建Bean并完成依赖注入。整个过程支持自定义排序、延迟加载和优先级控制。

阶段1:SpringApplication启动

核心入口:SpringApplication.run()

public class SpringApplication {public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);}public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);}// 核心run方法public ConfigurableApplicationContext run(String... args) {// 1. 创建StopWatch,记录启动时间StopWatch stopWatch = new StopWatch();stopWatch.start();// 2. 创建引导上下文DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 3. 配置headless属性configureHeadlessProperty();// 4. 获取SpringApplicationRunListeners并启动SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 5. 封装命令行参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 6. 准备环境ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);configureIgnoreBeanInfo(environment);// 7. 打印BannerBanner printedBanner = printBanner(environment);// 8. 创建ApplicationContext(重点)context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);// 9. 准备上下文(自动装配的入口)prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 10. 刷新上下文(Bean的创建和初始化)refreshContext(context);// 11. 刷新后的处理afterRefresh(context, applicationArguments);stopWatch.stop();// 12. 发布启动完成事件listeners.started(context);// 13. 调用RunnerscallRunners(context, applicationArguments);} catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);} catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}
}

阶段2:准备上下文(自动装配入口)

核心方法:prepareContext()

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 1. 设置环境context.setEnvironment(environment);// 2. 后置处理ApplicationContextpostProcessApplicationContext(context);// 3. 应用所有的ApplicationContextInitializerapplyInitializers(context);// 4. 发布上下文准备完成事件listeners.contextPrepared(context);// 5. 注册启动参数bootstrapContext.close(context);// 6. 打印启动信息if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 7. 注册单例BeanConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}// 8. 设置是否允许Bean定义覆盖if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 9. 加载LazyInitializationif (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 10. 获取所有的sources(包含主配置类)Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");// 11. 加载Bean定义(关键:这里会触发@EnableAutoConfiguration)load(context, sources.toArray(new Object[0]));// 12. 发布上下文加载完成事件listeners.contextLoaded(context);
}

阶段3:加载Bean定义

核心方法:load()

protected void load(ApplicationContext context, Object[] sources) {BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);if (this.beanNameGenerator != null) {loader.setBeanNameGenerator(this.beanNameGenerator);}if (this.resourceLoader != null) {loader.setResourceLoader(this.resourceLoader);}if (this.environment != null) {loader.setEnvironment(this.environment);}// 执行加载loader.load();
}// BeanDefinitionLoader.load()
private int load(Object source) {Assert.notNull(source, "Source must not be null");// 1. 如果是Class类型,使用AnnotatedBeanDefinitionReader加载if (source instanceof Class<?>) {return load((Class<?>) source);}// 2. 如果是Resource类型,使用XmlBeanDefinitionReader加载if (source instanceof Resource) {return load((Resource) source);}// 3. 如果是Package类型,使用ClassPathBeanDefinitionScanner扫描if (source instanceof Package) {return load((Package) source);}// 4. 如果是CharSequence类型,尝试加载类或资源if (source instanceof CharSequence) {return load((CharSequence) source);}throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

阶段4:处理@EnableAutoConfiguration

核心类:ConfigurationClassParser

public class ConfigurationClassParser {public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {// 解析注解配置类(主配置类会在这里被解析)parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}} catch (BeanDefinitionStoreException ex) {throw ex;}}// 处理延迟导入的配置(DeferredImportSelector)this.deferredImportSelectorHandler.process();}protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {// 1. 处理@Conditional注解if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}// 2. 处理@PropertySource注解processPropertySource(configClass);// 3. 处理@ComponentScan注解Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);// 4. 处理@Import注解(关键:这里会处理AutoConfigurationImportSelector)processImports(configClass, sourceClass, getImports(sourceClass), true);// 5. 处理@ImportResource注解processImportResource(configClass);// 6. 处理@Bean方法processBeanMethods(configClass);}
}

阶段5:AutoConfigurationImportSelector工作

核心类:AutoConfigurationImportSelector

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 1. 检查自动配置是否启用if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 2. 获取自动配置条目AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 3. 返回要导入的配置类名称数组return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 1. 获取@EnableAutoConfiguration注解的属性AnnotationAttributes attributes = getAttributes(annotationMetadata);// 2. 获取候选配置类(从spring.factories加载)List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 3. 去除重复的配置类configurations = removeDuplicates(configurations);// 4. 获取需要排除的配置类Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 5. 通过过滤器过滤配置类(关键:条件注解在这里生效)configurations = getConfigurationClassFilter().filter(configurations);// 6. 触发自动配置导入事件fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 从META-INF/spring.factories加载所有自动配置类List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. " +"If you are using a custom packaging, make sure that file is correct.");return configurations;}
}

阶段6:SpringFactoriesLoader加载配置

核心类:SpringFactoriesLoader

public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {// 1. 尝试从缓存获取MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 2. 加载所有的META-INF/spring.factories文件Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();// 3. 遍历所有的spring.factories文件while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);// 4. 加载PropertiesProperties properties = PropertiesLoaderUtils.loadProperties(resource);// 5. 解析配置for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();// 6. 将配置类名称按逗号分割并添加到结果中for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}// 7. 放入缓存cache.put(classLoader, result);return result;} catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);}}
}

spring.factories文件格式:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
# ... 更多配置类

阶段7:条件注解过滤

核心类:OnClassCondition

@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition extends FilteringSpringBootCondition {@Overridepublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {ClassLoader classLoader = context.getClassLoader();ConditionMessage matchMessage = ConditionMessage.empty();// 1. 获取@ConditionalOnClass注解的valueList<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);if (onClasses != null) {// 2. 检查类是否存在List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);// 3. 如果有缺失的类,返回不匹配if (!missing.isEmpty()) {return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class).didNotFind("required class", "required classes").items(Style.QUOTE, missing));}matchMessage = matchMessage.andCondition(ConditionalOnClass.class).found("required class", "required classes").items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));}// 4. 获取@ConditionalOnMissingClass注解的valueList<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);if (onMissingClasses != null) {// 5. 检查类是否不存在List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);// 6. 如果有存在的类,返回不匹配if (!present.isEmpty()) {return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class).found("unwanted class", "unwanted classes").items(Style.QUOTE, present));}matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class).didNotFind("unwanted class", "unwanted classes").items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));}return ConditionOutcome.match(matchMessage);}
}

条件注解示例:

@Configuration
@ConditionalOnClass(DataSource.class)  // 类路径存在DataSource类
@ConditionalOnMissingBean(DataSource.class)  // 容器中不存在DataSource Bean
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {@Bean@ConditionalOnProperty(prefix = "spring.datasource", name = "url")  // 配置文件存在指定属性public DataSource dataSource(DataSourceProperties properties) {return DataSourceBuilder.create().url(properties.getUrl()).username(properties.getUsername()).password(properties.getPassword()).build();}
}

阶段8:配置类排序

核心接口:AutoConfigurationSorter

class AutoConfigurationSorter {List<String> getInPriorityOrder(Collection<String> classNames) {// 1. 构建自动配置类的图结构AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory, this.autoConfigurationMetadata, classNames);List<String> orderedClassNames = new ArrayList<>(classNames);// 2. 按@AutoConfigureOrder排序orderedClassNames.sort((o1, o2) -> {int i1 = classes.get(o1).getOrder();int i2 = classes.get(o2).getOrder();return Integer.compare(i1, i2);});// 3. 处理@AutoConfigureBefore和@AutoConfigureAfterorderedClassNames = sortByAnnotation(classes, orderedClassNames);return orderedClassNames;}private List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {List<String> result = new ArrayList<>(classNames.size());Set<String> seen = new HashSet<>();for (String className : classNames) {doSortByAfterAnnotation(classes, className, result, seen, null);}return result;}
}

排序注解示例:

// WebMvcAutoConfiguration 在 DispatcherServletAutoConfiguration 之后配置
@Configuration
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
public class WebMvcAutoConfiguration {// ...
}// DataSourceAutoConfiguration 在 HibernateJpaAutoConfiguration 之前配置
@Configuration
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
public class DataSourceAutoConfiguration {// ...
}

完整流程时序图

用户代码                SpringApplication           ConfigurationClassParser      AutoConfigurationImportSelector|                            |                              |                                  ||--run()------------------>  |                              |                                  ||                            |--createApplicationContext()->|                                  ||                            |                              |                                  ||                            |--prepareContext()---------->|                                  ||                            |                              |                                  ||                            |                              |--parse()----------------------->||                            |                              |                                  ||                            |                              |                                  |--selectImports()|                            |                              |                                  ||                            |                              |                                  |--getCandidateConfigurations()|                            |                              |                                  |  (加载spring.factories)|                            |                              |                                  ||                            |                              |                                  |--filter()|                            |                              |                                  |  (条件注解过滤)|                            |                              |                                  ||                            |                              |<--(返回配置类列表)-------------||                            |                              |                                  ||                            |                              |--registerBeanDefinitions()       ||                            |                              |                                  ||                            |--refreshContext()---------->|                                  ||                            |  (创建Bean实例)             |                                  ||                            |                              |                                  ||<--(返回ApplicationContext)|                              |                                  |

源码流程总结:

  1. 启动阶段:SpringApplication.run() 创建并准备 ApplicationContext
  2. 加载阶段:通过 BeanDefinitionLoader 加载主配置类的 Bean 定义
  3. 解析阶段:ConfigurationClassParser 解析 @Import 注解,触发 AutoConfigurationImportSelector
  4. 选择阶段:从 spring.factories 加载所有候选自动配置类
  5. 过滤阶段:通过 @Conditional 系列注解过滤,只保留满足条件的配置类
  6. 排序阶段:根据 @AutoConfigureOrder、@AutoConfigureBefore、@AutoConfigureAfter 排序
  7. 注册阶段:将过滤后的配置类注册为 BeanDefinition
  8. 刷新阶段:refreshContext() 创建所有单例 Bean 实例

补充:@EnableAutoConfiguration 执行入口与生效机制

一、执行入口详解

核心问题:@EnableAutoConfiguration 注解是如何被触发执行的?

执行入口调用链:

SpringApplication.run()↓
AbstractApplicationContext.refresh()↓
invokeBeanFactoryPostProcessors()↓
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()↓
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()↓
ConfigurationClassPostProcessor.processConfigBeanDefinitions()↓
ConfigurationClassParser.parse()↓
ConfigurationClassParser.doProcessConfigurationClass()↓
ConfigurationClassParser.processImports()↓
DeferredImportSelectorHandler.process()↓
AutoConfigurationImportSelector.selectImports()

详细源码执行流程

入口1:AbstractApplicationContext.refresh()

@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1. 准备刷新上下文prepareRefresh();// 2. 获取BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3. 准备BeanFactoryprepareBeanFactory(beanFactory);try {// 4. 后置处理BeanFactorypostProcessBeanFactory(beanFactory);// 5. 调用BeanFactoryPostProcessor(关键入口)// @EnableAutoConfiguration 在这里开始执行invokeBeanFactoryPostProcessors(beanFactory);// 6. 注册BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 7. 初始化MessageSourceinitMessageSource();// 8. 初始化事件广播器initApplicationEventMulticaster();// 9. 刷新特定上下文的子类onRefresh();// 10. 注册监听器registerListeners();// 11. 实例化所有非懒加载的单例BeanfinishBeanFactoryInitialization(beanFactory);// 12. 完成刷新finishRefresh();} catch (BeansException ex) {destroyBeans();cancelRefresh(ex);throw ex;} finally {resetCommonCaches();}}
}

入口2:invokeBeanFactoryPostProcessors()

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {// 委托给PostProcessorRegistrationDelegate处理PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

入口3:PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {// 1. 首先处理BeanDefinitionRegistryPostProcessorSet<String> processedBeans = new HashSet<>();if (beanFactory instanceof BeanDefinitionRegistry) {BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();// 2. 分类处理for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {BeanDefinitionRegistryPostProcessor registryProcessor =(BeanDefinitionRegistryPostProcessor) postProcessor;registryProcessor.postProcessBeanDefinitionRegistry(registry);registryProcessors.add(registryProcessor);} else {regularPostProcessors.add(postProcessor);}}// 3. 获取所有的BeanDefinitionRegistryPostProcessorString[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);// 4. 按优先级排序并执行// ConfigurationClassPostProcessor 在这里被执行(关键!)List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();for (String ppName : postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));processedBeans.add(ppName);}}sortPostProcessors(priorityOrderedPostProcessors, beanFactory);registryProcessors.addAll(priorityOrderedPostProcessors);// 5. 调用postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);}
}

入口4:ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);if (this.registriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);}if (this.factoriesPostProcessed.contains(registryId)) {throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);}this.registriesPostProcessed.add(registryId);// 处理配置类Bean定义(关键调用)processConfigBeanDefinitions(registry);
}

入口5:ConfigurationClassPostProcessor.processConfigBeanDefinitions()

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();String[] candidateNames = registry.getBeanDefinitionNames();// 1. 找出所有的配置类候选者for (String beanName : candidateNames) {BeanDefinition beanDef = registry.getBeanDefinition(beanName);if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {// 已经处理过} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {// 是配置类,添加到候选列表configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));}}// 2. 如果没有找到配置类,直接返回if (configCandidates.isEmpty()) {return;}// 3. 按@Order排序configCandidates.sort((bd1, bd2) -> {int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());return Integer.compare(i1, i2);});// 4. 创建ConfigurationClassParser解析器ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());// 5. 循环解析所有配置类do {// 解析配置类(关键:这里会触发@EnableAutoConfiguration)parser.parse(candidates);parser.validate();Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());configClasses.removeAll(alreadyParsed);// 6. 读取配置类并注册BeanDefinitionif (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}this.reader.loadBeanDefinitions(configClasses);alreadyParsed.addAll(configClasses);candidates.clear();// 检查是否有新的候选配置类if (registry.getBeanDefinitionCount() > candidateNames.length) {String[] newCandidateNames = registry.getBeanDefinitionNames();Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}for (String candidateName : newCandidateNames) {if (!oldCandidateNames.contains(candidateName)) {BeanDefinition bd = registry.getBeanDefinition(candidateName);if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&!alreadyParsedClasses.contains(bd.getBeanClassName())) {candidates.add(new BeanDefinitionHolder(bd, candidateName));}}}candidateNames = newCandidateNames;}} while (!candidates.isEmpty());
}

入口6:ConfigurationClassParser.parse()

public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();try {if (bd instanceof AnnotatedBeanDefinition) {// 解析注解配置类(主配置类在这里)parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());} else {parse(bd.getBeanClassName(), holder.getBeanName());}} catch (BeanDefinitionStoreException ex) {throw ex;}}// 处理延迟导入选择器(关键:AutoConfigurationImportSelector在这里执行)this.deferredImportSelectorHandler.process();
}protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

入口7:ConfigurationClassParser.doProcessConfigurationClass()

上层调用链:

ConfigurationClassParser.parse(Set<BeanDefinitionHolder> configCandidates)↓
ConfigurationClassParser.parse(AnnotationMetadata metadata, String beanName)↓
ConfigurationClassParser.processConfigurationClass(ConfigurationClass configClass)↓
ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)  ← 当前方法

processConfigurationClass方法(直接上层调用):

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {// 1. 判断是否需要跳过(@Conditional条件判断)if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}// 2. 检查是否已经处理过该配置类ConfigurationClass existingClass = this.configurationClasses.get(configClass);if (existingClass != null) {if (configClass.isImported()) {if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}return;} else {this.configurationClasses.remove(configClass);}}// 3. 处理配置类(调用doProcessConfigurationClass)SourceClass sourceClass = asSourceClass(configClass, DEFAULT_EXCLUSION_FILTER);do {sourceClass = doProcessConfigurationClass(configClass, sourceClass);} while (sourceClass != null);// 4. 将配置类添加到已处理集合this.configurationClasses.put(configClass, configClass);
}

核心方法实现:

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {// 1. 处理@Component注解if (configClass.getMetadata().isAnnotated(Component.class.getName())) {processMemberClasses(configClass, sourceClass);}// 2. 处理@PropertySources注解for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}}// 3. 处理@ComponentScan注解Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty()) {for (AnnotationAttributes componentScan : componentScans) {Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());for (BeanDefinitionHolder holder : scannedBeanDefinitions) {parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());}}}// 4. 处理@Import注解(关键:这里会处理@EnableAutoConfiguration中的@Import)processImports(configClass, sourceClass, getImports(sourceClass), true);// 5. 处理@ImportResource注解AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 6. 处理@Bean方法Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}return null;
}

入口8:ConfigurationClassParser.processImports()

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports) {if (importCandidates.isEmpty()) {return;}// 循环导入检查if (checkForCircularImports && isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));} else {this.importStack.push(configClass);try {for (SourceClass candidate : importCandidates) {// 1. 如果是ImportSelector(AutoConfigurationImportSelector是其子接口)if (candidate.isAssignable(ImportSelector.class)) {Class<?> candidateClass = candidate.loadClass();ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry);// 2. 如果是DeferredImportSelector(AutoConfigurationImportSelector实现了这个接口)if (selector instanceof DeferredImportSelector) {// 添加到延迟处理器(关键:AutoConfigurationImportSelector在这里被添加)this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);} else {// 普通ImportSelector立即执行String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// 3. 如果是ImportBeanDefinitionRegistrarClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());} else {// 4. 普通配置类,递归处理this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));}}} catch (BeanDefinitionStoreException ex) {throw ex;} finally {this.importStack.pop();}}
}

入口9:DeferredImportSelectorHandler.process()

public void process() {List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;this.deferredImportSelectors = null;try {if (deferredImports != null) {DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);deferredImports.forEach(handler::register);// 处理所有延迟导入选择器(AutoConfigurationImportSelector.selectImports()在这里调用)handler.processGroupImports();}} finally {this.deferredImportSelectors = new ArrayList<>();}
}

入口10:AutoConfigurationImportSelector.selectImports()(最终执行)

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 获取自动配置条目AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 返回要导入的配置类名称数组return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

关键时机总结

@EnableAutoConfiguration 的执行时机:

  1. 时机:在 refresh() 方法的 invokeBeanFactoryPostProcessors() 阶段
  2. 触发器ConfigurationClassPostProcessor(一个BeanDefinitionRegistryPostProcessor
  3. 延迟执行AutoConfigurationImportSelector 实现了 DeferredImportSelector,会在所有普通配置类解析完成后才执行
  4. 执行顺序:在所有 @Configuration 类解析完成后,但在Bean实例化之前

为什么要延迟执行?

// 1. DeferredImportSelector 的特殊之处
public interface DeferredImportSelector extends ImportSelector {// 延迟执行,在所有@Configuration解析完成后才执行// 这样可以确保:// - 用户自定义的配置类已经加载// - 可以根据用户配置决定是否启用某些自动配置// - 避免循环依赖问题
}// 2. 执行顺序示例
@SpringBootApplication
public class Application {// 执行顺序:// 1. 先解析 @ComponentScan(扫描用户定义的Bean)// 2. 再解析 @EnableAutoConfiguration(自动配置)// 这样用户的配置可以覆盖自动配置
}

完整调用链路图

用户启动应用↓
SpringApplication.run()↓
【创建ApplicationContext】↓
AbstractApplicationContext.refresh()↓
【第5步】invokeBeanFactoryPostProcessors()  ← @EnableAutoConfiguration执行入口↓
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()↓
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry()↓
ConfigurationClassPostProcessor.processConfigBeanDefinitions()↓
ConfigurationClassParser.parse()↓
【解析主配置类】
ConfigurationClassParser.doProcessConfigurationClass()↓
【发现@Import(AutoConfigurationImportSelector.class)】
ConfigurationClassParser.processImports()↓
【识别为DeferredImportSelector,加入延迟队列】
DeferredImportSelectorHandler.handle()↓
【所有配置类解析完成后】
DeferredImportSelectorHandler.process()↓
【调用selectImports方法】
AutoConfigurationImportSelector.selectImports()↓
【加载spring.factories】
SpringFactoriesLoader.loadFactoryNames()↓
【条件过滤】
OnClassCondition.match()↓
【返回有效的自动配置类列表】↓
【注册BeanDefinition】
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()↓
【第11步】finishBeanFactoryInitialization()↓
【实例化Bean】
DefaultListableBeanFactory.preInstantiateSingletons()

二、生效机制详解

核心问题:@EnableAutoConfiguration 注解通过什么机制让自动配置生效?

生效机制的3个核心要素:

1. @Import 导入机制↓
2. ImportSelector 选择器↓
3. Conditional 条件注解

详细生效流程

第1步:@EnableAutoConfiguration 注解定义

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)  // 关键:通过@Import导入选择器
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";// 排除指定的自动配置类Class<?>[] exclude() default {};// 排除指定名称的自动配置类String[] excludeName() default {};
}

生效原理分析:

  • @Import 注解:Spring 的核心机制,用于导入配置类
  • AutoConfigurationImportSelector:实现了 DeferredImportSelector 接口,负责选择要导入的配置类
  • @AutoConfigurationPackage:自动配置包,注册主配置类所在的包

第2步:@Import 机制如何工作

@Import 的三种使用方式:

// 方式1:直接导入配置类
@Import(MyConfiguration.class)
public @interface EnableMyFeature {
}// 方式2:导入 ImportSelector(@EnableAutoConfiguration使用此方式)
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}// 方式3:导入 ImportBeanDefinitionRegistrar
@Import(MyBeanDefinitionRegistrar.class)
public @interface EnableMyRegistrar {
}

@Import 的处理流程:

// Spring 处理 @Import 注解的核心逻辑
public class ConfigurationClassParser {private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports) {for (SourceClass candidate : importCandidates) {// 判断导入类的类型if (candidate.isAssignable(ImportSelector.class)) {// 类型1:ImportSelectorClass<?> candidateClass = candidate.loadClass();ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);// 调用 Aware 接口invokeAwareMethods(selector);if (selector instanceof DeferredImportSelector) {// AutoConfigurationImportSelector 走这个分支this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);} else {// 普通 ImportSelector 立即执行String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// 类型2:ImportBeanDefinitionRegistrarClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());} else {// 类型3:普通配置类processConfigurationClass(candidate.asConfigClass(configClass));}}}
}

第3步:AutoConfigurationImportSelector 选择逻辑

核心方法:selectImports()

public class AutoConfigurationImportSelector implements DeferredImportSelector,BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 1. 检查自动配置功能是否开启if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 2. 获取自动配置的元信息AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 3. 返回需要导入的配置类名称数组return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}// 1. 获取注解属性(exclude、excludeName)AnnotationAttributes attributes = getAttributes(annotationMetadata);// 2. 从 spring.factories 加载候选配置类(核心)List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 3. 去重configurations = removeDuplicates(configurations);// 4. 处理排除的配置类Set<String> exclusions = getExclusions(annotationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 5. 过滤不满足条件的配置类(核心)configurations = getConfigurationClassFilter().filter(configurations);// 6. 触发自动配置导入事件fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}// 加载候选配置类protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 从 META-INF/spring.factories 文件加载配置类List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. " +"If you are using a custom packaging, make sure that file is correct.");return configurations;}
}

第4步:SpringFactoriesLoader 加载机制

META-INF/spring.factories 文件格式:

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

加载源码实现:

public final class SpringFactoriesLoader {public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";// 缓存,避免重复加载private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();public static List<String> loadFactoryNames(Class<?> factoryType, ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {// 1. 尝试从缓存获取MultiValueMap<String, String> result = cache.get(classLoader);if (result != null) {return result;}try {// 2. 加载所有 jar 包中的 META-INF/spring.factories 文件Enumeration<URL> urls = (classLoader != null ?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();// 3. 遍历所有 spring.factories 文件while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);// 4. 解析 properties 文件for (Map.Entry<?, ?> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue());// 5. 添加到结果集for (String factoryImplementationName : factoryImplementationNames) {result.add(factoryTypeName, factoryImplementationName.trim());}}}// 6. 放入缓存cache.put(classLoader, result);return result;} catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);}}
}

第5步:条件注解过滤(Conditional)

为什么需要条件注解?

// 问题:如果没有条件注解
@Configuration
public class DataSourceAutoConfiguration {@Beanpublic DataSource dataSource() {// 如果项目中没有引入数据库驱动,这里会报错return new HikariDataSource();}
}// 解决:使用条件注解
@Configuration
@ConditionalOnClass(DataSource.class)  // 只有存在 DataSource 类才生效
public class DataSourceAutoConfiguration {@Bean@ConditionalOnMissingBean  // 只有容器中不存在 DataSource 才创建public DataSource dataSource() {return new HikariDataSource();}
}

常用条件注解:

// 1. 类条件
@ConditionalOnClass(DataSource.class)  // 类路径存在指定类
@ConditionalOnMissingClass("com.example.MyClass")  // 类路径不存在指定类// 2. Bean条件
@ConditionalOnBean(DataSource.class)  // 容器中存在指定Bean
@ConditionalOnMissingBean(DataSource.class)  // 容器中不存在指定Bean// 3. 属性条件
@ConditionalOnProperty(name = "spring.datasource.url")  // 存在指定属性
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")  // 属性值匹配// 4. 资源条件
@ConditionalOnResource(resources = "classpath:app.properties")  // 存在指定资源// 5. Web应用条件
@ConditionalOnWebApplication(type = Type.SERVLET)  // 是Servlet Web应用
@ConditionalOnNotWebApplication  // 不是Web应用// 6. SpEL条件
@ConditionalOnExpression("${app.enabled:true}")  // SpEL表达式为true// 7. 单例条件
@ConditionalOnSingleCandidate(DataSource.class)  // 容器中只有一个候选Bean

条件注解的执行原理:

// 条件注解的核心处理类
class OnClassCondition extends FilteringSpringBootCondition {@Overridepublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {ClassLoader classLoader = context.getClassLoader();ConditionMessage matchMessage = ConditionMessage.empty();// 1. 获取 @ConditionalOnClass 的值List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);if (onClasses != null) {// 2. 检查类是否存在List<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);// 3. 如果有类不存在,返回不匹配if (!missing.isEmpty()) {return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class).didNotFind("required class", "required classes").items(Style.QUOTE, missing));}matchMessage = matchMessage.andCondition(ConditionalOnClass.class).found("required class", "required classes").items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));}return ConditionOutcome.match(matchMessage);}// 检查类是否存在protected enum ClassNameFilter {PRESENT {@Overridepublic boolean matches(String className, ClassLoader classLoader) {return isPresent(className, classLoader);}},MISSING {@Overridepublic boolean matches(String className, ClassLoader classLoader) {return !isPresent(className, classLoader);}};abstract boolean matches(String className, ClassLoader classLoader);static boolean isPresent(String className, ClassLoader classLoader) {try {forName(className, classLoader);return true;} catch (Throwable ex) {return false;}}}
}

第6步:完整的自动配置示例

以 DataSource 自动配置为例:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {// 1. 内部配置类:HikariDataSource 配置@Configuration(proxyBeanMethods = false)@ConditionalOnClass(HikariDataSource.class)@ConditionalOnMissingBean(DataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)static class Hikari {@Bean@ConfigurationProperties(prefix = "spring.datasource.hikari")HikariDataSource dataSource(DataSourceProperties properties) {HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);if (StringUtils.hasText(properties.getName())) {dataSource.setPoolName(properties.getName());}return dataSource;}}// 2. 内部配置类:Tomcat DataSource 配置@Configuration(proxyBeanMethods = false)@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)@ConditionalOnMissingBean(DataSource.class)@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource")static class Tomcat {@Bean@ConfigurationProperties(prefix = "spring.datasource.tomcat")org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);return dataSource;}}// 3. 通用的 DataSource 配置@Configuration(proxyBeanMethods = false)@ConditionalOnMissingBean(DataSource.class)@ConditionalOnProperty(name = "spring.datasource.type")static class Generic {@BeanDataSource dataSource(DataSourceProperties properties) {// 根据配置文件中的 spring.datasource.type 创建 DataSourcereturn properties.initializeDataSourceBuilder().build();}}
}

配置属性类:

@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {private ClassLoader classLoader;/*** 数据源类型,如果不指定,会根据类路径自动检测*/private Class<? extends DataSource> type;/*** JDBC 驱动类名*/private String driverClassName;/*** JDBC URL*/private String url;/*** 用户名*/private String username;/*** 密码*/private String password;// getters and setters...
}

生效机制总结图

@EnableAutoConfiguration↓
【通过 @Import 导入】↓
AutoConfigurationImportSelector↓
【实现 DeferredImportSelector 接口】↓
selectImports() 方法被调用↓
【从 META-INF/spring.factories 加载】↓
SpringFactoriesLoader.loadFactoryNames()↓
【返回所有自动配置类列表】↓
【条件注解过滤】
@ConditionalOnClass
@ConditionalOnMissingBean
@ConditionalOnProperty↓
【返回满足条件的配置类】↓
【注册 BeanDefinition】
ConfigurationClassBeanDefinitionReader↓
【创建 Bean 实例】
AbstractBeanFactory.getBean()↓
【自动配置生效】

关键机制总结

@EnableAutoConfiguration 生效的关键机制:

  1. @Import 机制

    • 通过 @Import(AutoConfigurationImportSelector.class) 导入选择器
    • Spring 在处理配置类时会识别 @Import 注解
  2. ImportSelector 接口

    • AutoConfigurationImportSelector 实现了 DeferredImportSelector
    • selectImports() 方法返回要导入的配置类名称数组
  3. SPI 机制

    • 通过 META-INF/spring.factories 文件定义自动配置类
    • SpringFactoriesLoader 加载所有 jar 包中的配置
  4. 条件注解

    • @ConditionalOnXxx 注解决定配置是否生效
    • 在配置类注册前进行条件判断
  5. 配置属性绑定

    • @ConfigurationProperties 绑定配置文件属性
    • @EnableConfigurationProperties 启用属性配置

生效流程简述:

  1. 解析 @EnableAutoConfiguration 注解
  2. 识别 @Import(AutoConfigurationImportSelector.class)
  3. 调用 AutoConfigurationImportSelector.selectImports()
  4. spring.factories 加载所有自动配置类
  5. 通过条件注解过滤不满足条件的配置类
  6. 注册满足条件的配置类到容器
  7. 创建配置类中定义的 Bean

19. Spring Boot 的配置文件优先级?

答案:
配置文件加载优先级(从高到低):

  1. 命令行参数
  2. JNDI 属性
  3. 系统属性
  4. 环境变量
  5. application-{profile}.properties/yml
  6. application.properties/yml
  7. @PropertySource 注解
  8. 默认属性

示例:

# application.yml
server:port: 8080# application-dev.yml
server:port: 8081# application-prod.yml
server:port: 8082

20. Spring 如何解析配置文件?源码流程详解

答案: Spring 通过多种方式解析配置文件,支持 XML、Properties、YAML 等格式。

2分钟面试表达:
Spring配置文件解析分为三个核心阶段:加载、解析、注入。首先,Spring通过PropertySource体系加载配置文件,支持XML、Properties、YAML等多种格式。然后通过PropertyResolver接口解析配置值,支持占位符、默认值、SpEL表达式等高级特性。最后通过@Value注解或@ConfigurationProperties将配置注入到Bean中。整个流程采用责任链模式,支持配置优先级和条件化加载。

源码解析流程:

1. XML配置文件解析源码流程

核心类:ClassPathXmlApplicationContext

// 1. 入口:ClassPathXmlApplicationContext构造器
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);
}// 2. 调用父类AbstractXmlApplicationContext的构造器
public AbstractXmlApplicationContext(ApplicationContext parent) {super(parent);
}// 3. 核心方法:loadBeanDefinitions
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// 创建XML Bean定义读取器XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// 配置读取器beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// 初始化读取器initBeanDefinitionReader(beanDefinitionReader);// 加载Bean定义loadBeanDefinitions(beanDefinitionReader);
}// 4. 加载Bean定义的具体实现
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}
}

XML解析核心:XmlBeanDefinitionReader

// 5. XmlBeanDefinitionReader.loadBeanDefinitions
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return loadBeanDefinitions(location, null);
}// 6. 解析XML文档
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 解析XML文档Document doc = doLoadDocument(inputSource, resource);// 注册Bean定义return registerBeanDefinitions(doc, resource);} catch (BeanDefinitionStoreException ex) {throw ex;}
}// 7. 注册Bean定义
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();int countBefore = getRegistry().getBeanDefinitionCount();documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;
}

2. Properties配置文件解析源码流程

核心类:PropertySourcesPlaceholderConfigurer

// 1. 属性占位符配置器
public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupportimplements EnvironmentAware {private PropertySources propertySources;private Environment environment;// 2. 处理属性占位符@Overrideprotected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {// 创建属性源MutablePropertySources propertySources = new MutablePropertySources();if (this.propertySources != null) {propertySources.addLast(this.propertySources);}// 添加环境属性源if (this.environment != null) {propertySources.addLast(new PropertiesPropertySource("environment", this.environment.getSystemProperties()));}// 处理占位符processProperties(beanFactory, new PropertySourcesPropertyResolver(propertySources));}
}

属性解析核心:PropertySourcesPropertyResolver

// 3. 属性源属性解析器
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {private final PropertySources propertySources;public PropertySourcesPropertyResolver(PropertySources propertySources) {this.propertySources = propertySources;}// 4. 解析属性值@Overrideprotected String getPropertyAsRawString(String key) {return getProperty(key, String.class, false);}// 5. 获取属性值protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {if (this.propertySources != null) {for (PropertySource<?> propertySource : this.propertySources) {Object value = propertySource.getProperty(key);if (value != null) {if (resolveNestedPlaceholders && value instanceof String) {value = resolveNestedPlaceholders((String) value);}return convertValueIfNecessary(value, targetValueType);}}}return null;}
}

3. YAML配置文件解析源码流程

核心类:YamlPropertiesFactoryBean

// 1. YAML属性工厂Bean
public class YamlPropertiesFactoryBean implements FactoryBean<Properties>, InitializingBean {private Resource[] resources = new Resource[0];private Yaml yaml;// 2. 创建YAML解析器@Overridepublic void afterPropertiesSet() throws Exception {if (this.yaml == null) {this.yaml = createYaml();}}// 3. 解析YAML文件@Overridepublic Properties getObject() throws Exception {Properties result = new Properties();if (!ObjectUtils.isEmpty(this.resources)) {for (Resource resource : this.resources) {if (resource.exists()) {// 解析YAML内容Map<String, Object> map = this.yaml.loadAs(new InputStreamReader(resource.getInputStream(), "UTF-8"), Map.class);// 转换为PropertiesPropertiesLoaderUtils.fillProperties(result, map);}}}return result;}
}

4. 配置注入源码流程

@Value注解处理:AutowiredAnnotationBeanPostProcessor

// 1. 自动装配注解Bean后处理器
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {// 2. 处理属性注入@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);} catch (BeanCreationException ex) {throw ex;}return pvs;}// 3. 注入属性值@Overrideprotected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;if (this.cached) {value = resolvedCachedArgument(beanName, this.cachedFieldValue);} else {// 解析属性值value = resolveFieldValue(field, bean, beanName);}if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}
}

@ConfigurationProperties处理:ConfigurationPropertiesBindingPostProcessor

// 4. 配置属性绑定后处理器
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {// 5. 绑定配置属性@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {ConfigurationProperties annotation = AnnotationUtils.findAnnotation(bean.getClass(), ConfigurationProperties.class);if (annotation != null) {// 绑定属性bind(bean, annotation);}return bean;}// 6. 执行属性绑定private void bind(Object bean, ConfigurationProperties annotation) {// 创建绑定器Binder binder = new Binder(ConfigurationPropertySources.from(environment));// 绑定属性BindResult<?> result = binder.bind(annotation.prefix(), bean.getClass());if (result.isBound()) {// 将绑定结果设置到Bean中BeanUtils.copyProperties(result.get(), bean);}}
}

5. 配置优先级源码实现

PropertySource体系

// 1. 属性源抽象类
public abstract class PropertySource<T> {protected final String name;protected final T source;public PropertySource(String name, T source) {this.name = name;this.source = source;}public abstract Object getProperty(String name);// 2. 属性源比较(用于优先级排序)@Overridepublic boolean equals(Object obj) {return (this == obj || (obj instanceof PropertySource &&ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) obj).name)));}
}// 3. 可变的属性源集合
public class MutablePropertySources implements PropertySources {private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();// 4. 添加属性源(按优先级)public void addFirst(PropertySource<?> propertySource) {removeIfPresent(propertySource);this.propertySourceList.add(0, propertySource);}public void addLast(PropertySource<?> propertySource) {removeIfPresent(propertySource);this.propertySourceList.add(propertySource);}
}

配置优先级实现

// 5. 标准环境实现
public class StandardEnvironment extends AbstractEnvironment {public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";// 6. 自定义属性源@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {// 系统属性(高优先级)propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));// 系统环境变量(低优先级)propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}
}

6. 占位符解析源码

占位符解析器

// 1. 属性占位符解析器
public class PropertyPlaceholderHelper {private static final String PLACEHOLDER_PREFIX = "${";private static final String PLACEHOLDER_SUFFIX = "}";private static final String VALUE_SEPARATOR = ":";// 2. 解析占位符public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {return parseStringValue(value, placeholderResolver, new HashSet<>());}// 3. 解析字符串值protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {StringBuilder result = new StringBuilder(strVal);int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX);while (startIndex != -1) {int endIndex = findPlaceholderEndIndex(result, startIndex);if (endIndex != -1) {// 提取占位符String placeholder = result.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);String originalPlaceholder = placeholder;if (!visitedPlaceholders.add(originalPlaceholder)) {throw new IllegalArgumentException("Circular placeholder reference '" + originalPlaceholder + "' in property definitions");}// 解析占位符值String propVal = placeholderResolver.resolvePlaceholder(placeholder);if (propVal == null && VALUE_SEPARATOR != null) {int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);if (separatorIndex != -1) {String actualPlaceholder = placeholder.substring(0, separatorIndex);String defaultValue = placeholder.substring(separatorIndex + VALUE_SEPARATOR.length());propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);if (propVal == null) {propVal = defaultValue;}}}if (propVal != null) {// 递归解析嵌套占位符propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);result.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal);startIndex = result.indexOf(PLACEHOLDER_PREFIX, startIndex + propVal.length());} else {startIndex = result.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());}visitedPlaceholders.remove(originalPlaceholder);} else {startIndex = -1;}}return result.toString();}
}

源码流程总结:

  1. 加载阶段:通过ResourceLoader加载配置文件,创建对应的PropertySource
  2. 解析阶段:使用PropertyResolver解析配置值,支持占位符、默认值、SpEL表达式
  3. 注入阶段:通过BeanPostProcessor将配置注入到Bean中
  4. 优先级:通过PropertySources的List顺序实现配置优先级
  5. 缓存:解析结果会被缓存,提高性能

Spring 设计模式

21. Spring 中使用了哪些设计模式?

答案:

Spring 框架大量使用了设计模式,体现了优秀框架的设计思想:

1. 单例模式 (Singleton Pattern)

// Spring 默认的 Bean 作用域就是单例
@Service
public class UserService {// Spring 容器中只有一个 UserService 实例
}// 配置单例模式
@Bean
@Scope("singleton")  // 默认就是单例
public UserService userService() {return new UserService();
}

2. 工厂模式 (Factory Pattern)

// BeanFactory 和 ApplicationContext 都是工厂
public interface BeanFactory {Object getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;
}// 使用工厂获取 Bean
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userService", UserService.class);

3. 代理模式 (Proxy Pattern)

// AOP 使用代理模式
@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void beforeMethod(JoinPoint joinPoint) {System.out.println("方法执行前");}
}// Spring 为 UserService 创建代理对象
@Service
public class UserService {public void saveUser(User user) {// 实际调用的是代理对象的方法}
}

4. 模板方法模式 (Template Method Pattern)

// JdbcTemplate 使用模板方法模式
@Repository
public class UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;public User findById(Long id) {return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?",new Object[]{id},(rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name")));}
}// 模板方法定义算法骨架
public abstract class JdbcTemplate {public final <T> T query(String sql, RowMapper<T> rowMapper) {// 1. 获取连接Connection conn = getConnection();try {// 2. 创建语句PreparedStatement stmt = conn.prepareStatement(sql);// 3. 执行查询ResultSet rs = stmt.executeQuery();// 4. 处理结果return rowMapper.mapRow(rs);} finally {// 5. 关闭资源closeConnection(conn);}}
}

5. 观察者模式 (Observer Pattern)

// Spring 事件机制使用观察者模式
// 发布事件
@Component
public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void createUser(User user) {userRepository.save(user);// 发布用户创建事件eventPublisher.publishEvent(new UserCreatedEvent(user));}
}// 监听事件
@Component
public class UserEventListener {@EventListenerpublic void handleUserCreated(UserCreatedEvent event) {System.out.println("用户创建事件: " + event.getUser());}
}

6. 策略模式 (Strategy Pattern)

// 不同的数据源策略
public interface DataSourceStrategy {Connection getConnection();
}@Component
public class MySQLDataSourceStrategy implements DataSourceStrategy {@Overridepublic Connection getConnection() {return DriverManager.getConnection("jdbc:mysql://localhost:3306/db");}
}@Component
public class PostgreSQLDataSourceStrategy implements DataSourceStrategy {@Overridepublic Connection getConnection() {return DriverManager.getConnection("jdbc:postgresql://localhost:5432/db");}
}@Service
public class DataService {@Autowiredprivate List<DataSourceStrategy> strategies;public void processData(String dbType) {DataSourceStrategy strategy = strategies.stream().filter(s -> s.getClass().getSimpleName().contains(dbType)).findFirst().orElseThrow(() -> new IllegalArgumentException("不支持的数据源"));Connection conn = strategy.getConnection();// 处理数据}
}

7. 适配器模式 (Adapter Pattern)

// HandlerAdapter 使用适配器模式
public interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}@Component
public class RequestMappingHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return handler instanceof HandlerMethod;}@Overridepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HandlerMethod handlerMethod = (HandlerMethod) handler;// 调用实际的 Controller 方法return invokeHandlerMethod(request, response, handlerMethod);}
}

8. 装饰器模式 (Decorator Pattern)

// Bean 的装饰器模式
public class BeanWrapperImpl implements BeanWrapper {private Object wrappedObject;public BeanWrapperImpl(Object object) {this.wrappedObject = object;}@Overridepublic void setPropertyValue(String propertyName, Object value) {// 装饰原有的对象,添加属性设置功能PropertyDescriptor pd = getPropertyDescriptor(propertyName);Method writeMethod = pd.getWriteMethod();try {writeMethod.invoke(wrappedObject, value);} catch (Exception e) {throw new BeanException("设置属性失败", e);}}
}

9. 建造者模式 (Builder Pattern)

// Spring Boot 的配置构建
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {private String url;private String username;private String password;// Builder 模式public static class Builder {private DataSourceProperties properties = new DataSourceProperties();public Builder url(String url) {properties.url = url;return this;}public Builder username(String username) {properties.username = username;return this;}public Builder password(String password) {properties.password = password;return this;}public DataSourceProperties build() {return properties;}}
}

10. 责任链模式 (Chain of Responsibility Pattern)

// Spring Security 的过滤器链
public class FilterChainProxy implements Filter {private List<SecurityFilterChain> filterChains;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;// 找到匹配的过滤器链for (SecurityFilterChain filterChain : filterChains) {if (filterChain.matches(httpRequest)) {// 执行过滤器链filterChain.doFilter(request, response, chain);return;}}chain.doFilter(request, response);}
}

设计模式总结:

  • 单例模式:Bean 的默认作用域
  • 工厂模式:BeanFactory 和 ApplicationContext
  • 代理模式:AOP 实现
  • 模板方法模式:JdbcTemplate、RestTemplate
  • 观察者模式:事件发布订阅机制
  • 策略模式:多种数据源、缓存策略
  • 适配器模式:HandlerAdapter
  • 装饰器模式:BeanWrapper
  • 建造者模式:配置构建
  • 责任链模式:过滤器链

Spring Security

22. Spring Security 的核心概念?

答案:

核心组件:

  • Authentication: 认证(你是谁)
  • Authorization: 授权(你能做什么)
  • Principal: 主体(用户)
  • GrantedAuthority: 权限
  • SecurityContext: 安全上下文

认证流程:

  1. 用户提交凭证
  2. AuthenticationManager 验证
  3. AuthenticationProvider 处理认证
  4. 认证成功创建 Authentication 对象
  5. 存储到 SecurityContext

23. Spring Security 的配置方式?

答案:

基于注解:

@EnableWebSecurity
@Configuration
public class SecurityConfig {@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(authz -> authz.requestMatchers("/public/**").permitAll().requestMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated()).formLogin(form -> form.loginPage("/login").defaultSuccessUrl("/dashboard")).logout(logout -> logout.logoutUrl("/logout").logoutSuccessUrl("/login"));return http.build();}
}

方法级安全:

@Service
public class UserService {@PreAuthorize("hasRole('ADMIN')")public void deleteUser(Long id) {// 只有 ADMIN 角色可以执行}@PostAuthorize("returnObject.owner == authentication.name")public User getUser(Long id) {// 只能访问自己的用户信息return userRepository.findById(id);}
}

Spring Data

24. Spring Data JPA 的优势?

答案:

核心优势:

  • Repository 抽象: 简化数据访问层
  • 方法命名查询: 根据方法名自动生成查询
  • @Query 注解: 自定义 JPQL 或原生 SQL
  • 分页和排序: 内置分页支持
  • 审计功能: 自动记录创建/修改时间

示例:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {// 方法命名查询List<User> findByName(String name);List<User> findByNameAndAge(String name, Integer age);// 自定义查询@Query("SELECT u FROM User u WHERE u.email = ?1")User findByEmail(String email);// 原生 SQL@Query(value = "SELECT * FROM users WHERE age > ?1", nativeQuery = true)List<User> findByAgeGreaterThan(Integer age);// 分页查询Page<User> findByNameContaining(String name, Pageable pageable);
}

25. Spring Data 的事务管理?

答案:

声明式事务:

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactional(readOnly = true)public User findById(Long id) {return userRepository.findById(id).orElse(null);}@Transactional(rollbackFor = Exception.class)public User save(User user) {return userRepository.save(user);}@Transactional(propagation = Propagation.REQUIRES_NEW)public void logUserAction(String action) {// 新事务中记录日志}
}

事务传播行为:

  • REQUIRED: 默认,加入现有事务或创建新事务
  • REQUIRES_NEW: 总是创建新事务
  • SUPPORTS: 支持事务,没有事务也能执行
  • NOT_SUPPORTED: 不支持事务
  • MANDATORY: 必须在事务中执行
  • NEVER: 不能在事务中执行
  • NESTED: 嵌套事务

Spring Cloud

26. Spring Cloud 的核心组件?

答案:

服务发现:

  • Eureka: 服务注册与发现
  • Consul: 多数据中心服务发现
  • Zookeeper: 分布式协调服务

负载均衡:

  • Ribbon: 客户端负载均衡
  • LoadBalancer: Spring Cloud LoadBalancer

服务调用:

  • Feign: 声明式 HTTP 客户端
  • OpenFeign: Feign 的增强版

服务网关:

  • Gateway: 响应式网关
  • Zuul: 传统网关

配置管理:

  • Config: 分布式配置中心

熔断器:

  • Hystrix: 熔断器模式实现
  • Resilience4j: 轻量级熔断器

27. Spring Cloud Gateway 的工作原理?

答案:

核心概念:

  • Route: 路由,定义请求如何转发
  • Predicate: 断言,匹配请求条件
  • Filter: 过滤器,处理请求和响应

工作流程:

  1. 客户端发送请求到 Gateway
  2. Gateway Handler Mapping 查找匹配的路由
  3. Gateway Web Handler 处理请求
  4. 执行过滤器链(Pre Filter)
  5. 代理到目标服务
  6. 执行过滤器链(Post Filter)
  7. 返回响应给客户端

配置示例:

spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/api/users/**filters:- StripPrefix=2- AddRequestHeader=X-Gateway, Spring-Cloud

事务管理

28. Spring 事务管理的两种方式?

答案:

编程式事务:

@Service
public class UserService {@Autowiredprivate TransactionTemplate transactionTemplate;public void transferMoney(Long fromId, Long toId, BigDecimal amount) {transactionTemplate.execute(status -> {try {// 业务逻辑accountService.debit(fromId, amount);accountService.credit(toId, amount);return null;} catch (Exception e) {status.setRollbackOnly();throw e;}});}
}

声明式事务:

@Service
@Transactional
public class UserService {@Transactional(rollbackFor = Exception.class)public void transferMoney(Long fromId, Long toId, BigDecimal amount) {accountService.debit(fromId, amount);accountService.credit(toId, amount);}
}

29. Spring 事务的传播行为和隔离级别?

答案:

事务传播行为(Propagation):

  1. REQUIRED(默认):如果存在事务则加入,否则创建新事务
  2. REQUIRES_NEW:总是创建新事务,挂起当前事务
  3. SUPPORTS:如果存在事务则加入,否则以非事务方式执行
  4. NOT_SUPPORTED:以非事务方式执行,挂起当前事务
  5. MANDATORY:必须在事务中执行,否则抛出异常
  6. NEVER:必须在非事务中执行,否则抛出异常
  7. NESTED:嵌套事务,如果存在事务则创建嵌套事务

传播行为示例:

@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 如果调用方有事务则加入,否则创建新事务methodB();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// 总是创建新事务,挂起methodA的事务// 即使methodA回滚,methodB也会提交}@Transactional(propagation = Propagation.NESTED)public void methodC() {// 嵌套事务,如果methodA回滚,methodC也会回滚// 但methodC回滚不会影响methodA}
}

事务隔离级别(Isolation):

  1. READ_UNCOMMITTED(读未提交):最低级别,可能读到脏数据
  2. READ_COMMITTED(读已提交):避免脏读,可能出现不可重复读
  3. REPEATABLE_READ(可重复读):避免脏读和不可重复读,可能出现幻读
  4. SERIALIZABLE(串行化):最高级别,完全避免并发问题

隔离级别示例:

@Service
public class UserService {@Transactional(isolation = Isolation.READ_COMMITTED)public void readUser() {// 读已提交,避免脏读User user = userRepository.findById(1L);}@Transactional(isolation = Isolation.REPEATABLE_READ)public void updateUser() {// 可重复读,避免不可重复读User user1 = userRepository.findById(1L);// 其他事务修改了数据User user2 = userRepository.findById(1L); // user1 == user2}@Transactional(isolation = Isolation.SERIALIZABLE)public void criticalOperation() {// 串行化,完全避免并发问题,但性能最差}
}

并发问题详解:

脏读(Dirty Read)

// 事务A修改数据但未提交
UPDATE user SET name = 'new_name' WHERE id = 1;// 事务B读取到未提交的数据(脏数据)
SELECT name FROM user WHERE id = 1; // 返回 'new_name'// 事务A回滚,但事务B已经读到了脏数据

不可重复读(Non-Repeatable Read)

// 事务A第一次读取
SELECT name FROM user WHERE id = 1; // 返回 'old_name'// 事务B修改并提交
UPDATE user SET name = 'new_name' WHERE id = 1;
COMMIT;// 事务A第二次读取
SELECT name FROM user WHERE id = 1; // 返回 'new_name'(不一致)

幻读(Phantom Read)

// 事务A第一次查询
SELECT COUNT(*) FROM user WHERE age > 18; // 返回 100// 事务B插入新数据并提交
INSERT INTO user (name, age) VALUES ('new_user', 20);
COMMIT;// 事务A第二次查询
SELECT COUNT(*) FROM user WHERE age > 18; // 返回 101(幻读)

实际应用场景:

@Service
public class OrderService {// 订单创建:需要新事务,避免影响其他操作@Transactional(propagation = Propagation.REQUIRES_NEW)public void createOrder(Order order) {orderRepository.save(order);}// 用户查询:读已提交,避免脏读@Transactional(isolation = Isolation.READ_COMMITTED, readOnly = true)public User getUser(Long id) {return userRepository.findById(id);}// 财务操作:串行化,确保数据一致性@Transactional(isolation = Isolation.SERIALIZABLE)public void transferMoney(Long fromId, Long toId, BigDecimal amount) {// 转账操作}
}

30. @Transactional 注解的失效场景?

答案:

常见失效场景:

  1. 方法不是 public - 事务代理只能拦截public方法
  2. 同类内部调用 - 绕过代理,直接调用方法
  3. 异常被捕获 - 异常被try-catch捕获,事务无法回滚
  4. Bean 没有被 Spring 管理 - 没有@Component等注解
  5. 事务传播行为设置错误 - 如设置为NOT_SUPPORTED

示例:

@Service
public class UserService {// 失效1:同类内部调用public void methodA() {this.methodB(); // 不会开启事务,绕过代理}@Transactionalpublic void methodB() {// 事务不会生效}// 失效2:异常被捕获@Transactionalpublic void methodC() {try {// 业务逻辑throw new RuntimeException();} catch (Exception e) {// 异常被捕获,事务不会回滚}}// 失效3:方法不是public@Transactionalprivate void methodD() {// 事务不会生效,代理无法拦截private方法}// 失效4:事务传播行为设置错误@Transactional(propagation = Propagation.NOT_SUPPORTED)public void methodE() {// 不支持事务,即使有@Transactional也不会生效}
}// 失效5:Bean没有被Spring管理
public class UserService {  // 没有@Service注解@Transactionalpublic void methodF() {// 事务不会生效,Spring无法管理这个Bean}
}

Bean 生命周期

31. Spring Bean 的生命周期?

答案:

完整生命周期:

  1. 实例化: 创建 Bean 实例
  2. 属性填充: 注入依赖
  3. BeanNameAware.setBeanName()
  4. BeanFactoryAware.setBeanFactory()
  5. ApplicationContextAware.setApplicationContext()
  6. BeanPostProcessor.postProcessBeforeInitialization()
  7. @PostConstruct 或 InitializingBean.afterPropertiesSet()
  8. 自定义 init-method
  9. BeanPostProcessor.postProcessAfterInitialization()
  10. Bean 就绪,可以使用
  11. @PreDestroy 或 DisposableBean.destroy()
  12. 自定义 destroy-method

示例:

@Component
public class MyBean implements BeanNameAware, InitializingBean, DisposableBean {@PostConstructpublic void init() {System.out.println("PostConstruct");}@PreDestroypublic void cleanup() {System.out.println("PreDestroy");}@Overridepublic void setBeanName(String name) {System.out.println("BeanName: " + name);}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet");}@Overridepublic void destroy() throws Exception {System.out.println("destroy");}
}

32. Bean 的作用域有哪些?

答案:

Spring Bean 作用域:

  • singleton: 单例(默认)
  • prototype: 原型,每次获取都创建新实例
  • request: Web 环境,每个 HTTP 请求一个实例
  • session: Web 环境,每个 HTTP 会话一个实例
  • application: Web 环境,每个 ServletContext 一个实例
  • websocket: WebSocket 环境

配置方式:

@Component
@Scope("prototype")
public class PrototypeBean {// 每次获取都是新实例
}@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {// 每个请求一个实例
}

高级特性

33. Spring 的事件机制?

答案:

事件发布:

@Service
public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void createUser(User user) {// 创建用户userRepository.save(user);// 发布事件eventPublisher.publishEvent(new UserCreatedEvent(user));}
}

事件监听:

@Component
public class UserEventListener {@EventListenerpublic void handleUserCreated(UserCreatedEvent event) {System.out.println("用户创建事件: " + event.getUser());}@Async@EventListenerpublic void handleUserCreatedAsync(UserCreatedEvent event) {// 异步处理事件}
}

自定义事件:

public class UserCreatedEvent extends ApplicationEvent {private final User user;public UserCreatedEvent(Object source, User user) {super(source);this.user = user;}public User getUser() {return user;}
}

34. Spring 的循环依赖问题?

答案:

Spring的循环依赖是指两个或多个Bean相互依赖,形成循环引用。Spring通过三级缓存机制解决单例Bean的Setter注入循环依赖问题。

核心原理:当创建Bean A时,发现它依赖Bean B,此时A还未完全初始化,但Spring会将A的早期引用(半成品对象)放入三级缓存。然后去创建Bean B,B需要注入A时,从三级缓存中获取A的早期引用,完成B的创建。最后再完成A的初始化。这样就打破了循环。

三级缓存:一级缓存存储完整Bean,二级缓存存储早期Bean引用,三级缓存存储Bean工厂。

重要限制:只能解决单例Bean的Setter注入,构造器注入和原型Bean的循环依赖无法解决,因为构造器注入时对象还未创建,无法提前暴露引用。

面试加分项:可以提及为什么需要三级缓存而不是二级,原因是为了处理AOP代理,确保注入的是代理对象而不是原始对象。


详细技术说明:

什么是循环依赖?
循环依赖是指两个或多个Bean相互依赖,形成循环引用。比如A依赖B,B又依赖A。

循环依赖类型:

  1. 构造器循环依赖: 无法解决,会抛出异常
  2. Setter循环依赖: 可以解决(通过三级缓存)
  3. 原型Bean循环依赖: 无法解决

问题示例:

@Service
public class UserService {@Autowiredprivate OrderService orderService;  // UserService依赖OrderServicepublic void createUser() {orderService.createOrder();}
}@Service
public class OrderService {@Autowiredprivate UserService userService;    // OrderService依赖UserServicepublic void createOrder() {userService.createUser();}
}

Spring解决机制(三级缓存):

第1步:创建UserService实例

// Spring容器开始创建UserService
UserService userService = new UserService();  // 创建实例,但未完成初始化

第2步:发现循环依赖

// 尝试注入OrderService时发现循环依赖
// 将UserService放入三级缓存(早期暴露)
earlySingletonObjects.put("userService", userService);

第3步:创建OrderService实例

// 创建OrderService实例
OrderService orderService = new OrderService();

第4步:注入UserService

// 从三级缓存获取UserService(早期暴露的版本)
orderService.setUserService(earlySingletonObjects.get("userService"));

第5步:完成初始化

// 完成OrderService初始化
// 完成UserService初始化

三级缓存详解:

  • 一级缓存(singletonObjects): 存储完整的单例Bean
  • 二级缓存(earlySingletonObjects): 存储早期暴露的单例Bean
  • 三级缓存(singletonFactories): 存储单例Bean工厂

为什么构造器循环依赖无法解决?

@Service
public class ServiceA {private ServiceB serviceB;public ServiceA(ServiceB serviceB) {  // 构造器注入this.serviceB = serviceB;}
}@Service
public class ServiceB {private ServiceA serviceA;public ServiceB(ServiceA serviceA) {  // 构造器注入this.serviceA = serviceA;}
}

构造器注入时,Bean还没有创建完成,无法放入缓存,所以无法解决循环依赖。

面试要点:

  • 只有单例Bean的Setter注入可以解决循环依赖
  • 三级缓存机制是Spring解决循环依赖的核心
  • 构造器注入和原型Bean的循环依赖无法解决

三级缓存源码实现(DefaultSingletonBeanRegistry):

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {// 一级缓存:存储完整的单例Bean(成品对象)private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存储早期的单例Bean引用(半成品对象,已实例化但未初始化)private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);// 三级缓存:存储单例Bean工厂(用于创建早期引用)private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 获取单例Bean(核心方法)protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 从一级缓存获取完整BeanObject singletonObject = this.singletonObjects.get(beanName);// 2. 如果一级缓存没有,且Bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 3. 从二级缓存获取早期Bean引用singletonObject = this.earlySingletonObjects.get(beanName);// 4. 如果二级缓存也没有,且允许早期引用if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 双重检查singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {// 5. 从三级缓存获取Bean工厂ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 6. 通过工厂创建早期Bean引用singletonObject = singletonFactory.getObject();// 7. 放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 8. 从三级缓存移除this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}// 添加单例Bean工厂到三级缓存protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 放入三级缓存this.singletonFactories.put(beanName, singletonFactory);// 从二级缓存移除this.earlySingletonObjects.remove(beanName);}}}
}

为什么需要三级缓存?

// 问题:为什么不直接用二级缓存?
// 答案:为了处理AOP代理对象// 场景:如果Bean需要被AOP代理
@Service
public class UserService {@Autowiredprivate OrderService orderService;@Transactional  // 需要AOP代理public void createUser() {orderService.createOrder();}
}// 三级缓存中存储的是ObjectFactory
addSingletonFactory("userService", () -> {// 如果需要AOP,返回代理对象// 如果不需要AOP,返回原始对象return getEarlyBeanReference(beanName, mbd, bean);
});// getEarlyBeanReference方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果是AOP代理,这里会返回代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

完整的循环依赖解决流程(带AOP):

// 1. 创建UserService实例
UserService userService = new UserService();  // 原始对象// 2. 将ObjectFactory放入三级缓存(而不是直接放对象)
addSingletonFactory("userService", () -> getEarlyBeanReference("userService", mbd, userService));// 3. 属性注入时发现需要OrderService,去创建OrderService// 4. 创建OrderService实例
OrderService orderService = new OrderService();// 5. OrderService需要注入UserService,调用getSingleton("userService")
// 从三级缓存获取ObjectFactory,调用getObject()
// 如果UserService需要AOP,返回代理对象;否则返回原始对象
Object earlyUserService = singletonFactory.getObject();// 6. 将早期引用放入二级缓存,从三级缓存移除
earlySingletonObjects.put("userService", earlyUserService);
singletonFactories.remove("userService");// 7. OrderService注入完成,放入一级缓存// 8. UserService继续初始化,完成后也放入一级缓存

面试要点总结:

  1. 能解决的:单例Bean + Setter注入(字段注入、@Autowired)
  2. 不能解决的:构造器注入、原型Bean、多例Bean
  3. 核心机制:三级缓存 + 早期暴露
  4. 为什么三级:支持AOP代理,确保注入的是代理对象
  5. 检测时机:在Bean创建过程中,通过isSingletonCurrentlyInCreation判断

总结

Spring 框架是 Java 企业级开发的核心技术栈,掌握 Spring 的各个模块和特性对于 Java 开发者至关重要。本面试宝典涵盖了 Spring 的核心概念、IoC 容器、AOP、MVC、Boot、Security、Data、Cloud 等主要模块,以及事务管理、Bean 生命周期等高级特性。

重点掌握:

  • IoC 和 DI 的原理和实现
  • AOP 的切面编程思想
  • Spring Boot 的自动配置机制
  • 事务管理的使用和注意事项
  • Bean 的生命周期和作用域
  • 循环依赖的解决机制

通过深入理解这些概念和原理,能够在面试中展现出扎实的 Spring 技术功底。

http://www.dtcms.com/a/462669.html

相关文章:

  • 阳朔县建设规划局网站备案域名租用
  • 网站建设需要哪些工具与知识wordpress图片分享主题
  • 智能化 DDOS 防护平台架构与演进方向
  • 中石化网站是哪个公司做的做企业网站用什么框架
  • 第二步:创建写接口的模块,建立moogodb数据库连接,写添加与查询接口
  • 滑动窗口题目:K 个不同整数的子数组
  • qq网站临时会话静态网站跟动态的区别
  • 阿里云万网建网站家居企业网站建设报价
  • VBA效率大揭秘:选对数据结构,性能飙升300%!
  • LLM 论文精读(九)A Survey of Reinforcement Learning for Large Reasoning Models
  • The “Next“-价值度量与评估
  • 深圳营销网站建设多少钱frontpage网页制作实例
  • 家用电器行业外贸建站世界工厂采购网app
  • synchronized (Java)
  • LINUX——调试器gdb/cgdb的使用
  • GIS实战:投影变换教程与问题解答(上)
  • 项目(3) - LVGL 图形用户界面(GUI)库
  • 长春专业网站推广给我高清电影
  • Redis07-面试题
  • 甘肃省建设社厅网站电商要怎么做起来
  • 做软件常用的网站四川建筑职业技术学院教务网
  • 公司营业执照可以做几个网站微信小程序怎么制作自己的程序
  • 磁悬浮轴承的“眼睛”与“神经”:位移传感原理深度解析
  • Linux小课堂: 从TTY到图形化终端的完整解析
  • 网站带后台免费下载搜图片找原图
  • 网站怎么快速收录wordpress 文件 钩子
  • 互联网科技公司做网站哪家好农场游戏系统开发 网站建设推广
  • PyTorch 模型部署实战:用 Flask 搭图像分类 API
  • 如何进行目的地网站建设东莞厚街创新科技职业学院
  • 网站标题修改重庆网站设计排名