Java秋招之Spring生态系统
第6章 Spring生态系统
面试重要程度:⭐⭐⭐⭐⭐
常见提问方式:Spring IOC原理、AOP实现、循环依赖解决
预计阅读时间:45分钟
开场白
兄弟,Spring绝对是Java后端面试的重中之重!我敢说,99%的Java面试都会问到Spring相关的问题。不管是IOC、AOP,还是Spring Boot,这些都是必考内容。
今天我们就把Spring的核心原理彻底搞清楚,让你在面试中展现出对Spring框架的深度理解。
🌱 6.1 Spring Boot 3.0+新特性
GraalVM原生镜像支持
面试热点:
面试官:"Spring Boot 3.0有什么重要的新特性?GraalVM原生镜像有什么优势?"
核心特性:
// 1. 支持AOT(Ahead-of-Time)编译 @SpringBootApplication public class NativeApplication { public static void main(String[] args) { SpringApplication.run(NativeApplication.class, args); } } // 2. 构建原生镜像 // mvn -Pnative native:compile // 或者使用Docker // docker build -f Dockerfile.native -t myapp-native .
原生镜像的优势:
启动时间:从秒级降到毫秒级(50-100ms) 内存占用:从几百MB降到几十MB 镜像大小:从几百MB降到几十MB 冷启动:适合Serverless和容器化场景
实际对比:
# 传统JVM应用 启动时间:2-5秒 内存占用:200-500MB 镜像大小:200-300MB # GraalVM原生镜像 启动时间:50-100ms 内存占用:20-50MB 镜像大小:50-100MB
响应式编程WebFlux
面试重点:
// 传统的Spring MVC(阻塞式) @RestController public class TraditionalController { @Autowired private UserService userService; @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { return userService.findById(id); // 阻塞调用 } } // Spring WebFlux(响应式) @RestController public class ReactiveController { @Autowired private ReactiveUserService userService; @GetMapping("/users/{id}") public Mono<User> getUser(@PathVariable Long id) { return userService.findById(id); // 非阻塞调用 } @GetMapping("/users") public Flux<User> getAllUsers() { return userService.findAll() .delayElements(Duration.ofMillis(100)); // 背压处理 } }
响应式编程的优势:
// 高并发处理能力 @Service public class ReactiveUserService { @Autowired private ReactiveUserRepository repository; public Flux<User> findAll() { return repository.findAll() .publishOn(Schedulers.parallel()) // 并行处理 .map(this::enrichUser) // 数据增强 .filter(user -> user.isActive()) // 过滤 .onErrorResume(ex -> { // 错误处理 log.error("Error processing user", ex); return Flux.empty(); }); } private User enrichUser(User user) { // 异步调用其他服务 return user; } }
🏗️ 6.2 IOC容器核心原理
Bean生命周期详解
面试必问:
面试官:"说说Spring Bean的生命周期,每个阶段都做什么?"
完整生命周期:
@Component public class LifecycleBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { private String beanName; private BeanFactory beanFactory; private ApplicationContext applicationContext; // 1. 构造器 public LifecycleBean() { System.out.println("1. 构造器执行"); } // 2. 设置属性 @Value("${app.name:default}") private String appName; // 3. Aware接口回调 @Override public void setBeanName(String name) { this.beanName = name; System.out.println("3. setBeanName: " + name); } @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; System.out.println("3. setBeanFactory"); } @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; System.out.println("3. setApplicationContext"); } // 4. BeanPostProcessor前置处理 // 由框架调用,这里只是说明 // 5. InitializingBean接口 @Override public void afterPropertiesSet() { System.out.println("5. afterPropertiesSet"); } // 6. 自定义初始化方法 @PostConstruct public void customInit() { System.out.println("6. @PostConstruct"); } // 7. BeanPostProcessor后置处理 // 由框架调用,这里只是说明 // 8. Bean可以使用了 public void doSomething() { System.out.println("8. Bean正在工作..."); } // 9. DisposableBean接口 @Override public void destroy() { System.out.println("9. destroy"); } // 10. 自定义销毁方法 @PreDestroy public void customDestroy() { System.out.println("10. @PreDestroy"); } }
自定义BeanPostProcessor:
@Component public class CustomBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { if (bean instanceof LifecycleBean) { System.out.println("4. BeanPostProcessor前置处理: " + beanName); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof LifecycleBean) { System.out.println("7. BeanPostProcessor后置处理: " + beanName); } return bean; } }
循环依赖三级缓存解决方案
面试高频:
面试官:"Spring是如何解决循环依赖的?三级缓存是什么?"
循环依赖场景:
@Service public class ServiceA { @Autowired private ServiceB serviceB; public void methodA() { serviceB.methodB(); } } @Service public class ServiceB { @Autowired private ServiceA serviceA; public void methodB() { serviceA.methodA(); } }
三级缓存机制:
public class DefaultSingletonBeanRegistry { // 一级缓存:完成初始化的单例Bean private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 二级缓存:完成实例化但未初始化的Bean private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 三级缓存:单例Bean的工厂 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 1. 从一级缓存获取 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 2. 从二级缓存获取 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 3. 从三级缓存获取 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); // 放入二级缓存 this.earlySingletonObjects.put(beanName, singletonObject); // 从三级缓存移除 this.singletonFactories.remove(beanName); } } } } return singletonObject; } }
解决过程详解:
// 循环依赖解决过程 // 1. 创建ServiceA // - 实例化ServiceA(构造器) // - 将ServiceA的ObjectFactory放入三级缓存 // - 填充ServiceA的属性(发现需要ServiceB) // 2. 创建ServiceB // - 实例化ServiceB(构造器) // - 将ServiceB的ObjectFactory放入三级缓存 // - 填充ServiceB的属性(发现需要ServiceA) // 3. 获取ServiceA // - 从三级缓存获取ServiceA的ObjectFactory // - 调用ObjectFactory.getObject()获取ServiceA实例 // - 将ServiceA放入二级缓存,从三级缓存移除 // 4. ServiceB初始化完成 // - ServiceB获得ServiceA的引用 // - ServiceB初始化完成,放入一级缓存 // 5. ServiceA初始化完成 // - ServiceA获得ServiceB的引用 // - ServiceA初始化完成,放入一级缓存
@Autowired vs @Resource
面试对比:
@Service public class InjectionDemo { // @Autowired:Spring注解,按类型注入 @Autowired private UserService userService1; // @Autowired + @Qualifier:指定Bean名称 @Autowired @Qualifier("userServiceImpl") private UserService userService2; // @Resource:JDK注解,按名称注入 @Resource(name = "userServiceImpl") private UserService userService3; // @Resource:如果不指定name,按字段名查找 @Resource private UserService userServiceImpl; // 会查找名为userServiceImpl的Bean }
注入顺序对比:
@Autowired注入顺序: 1. 按类型查找Bean 2. 如果有多个,按@Primary注解 3. 如果没有@Primary,按@Qualifier指定 4. 如果没有@Qualifier,按字段名匹配 @Resource注入顺序: 1. 如果指定name,按name查找 2. 如果没有指定name,按字段名查找 3. 如果按名称找不到,按类型查找 4. 如果按类型找到多个,报错
🎯 6.3 AOP面向切面编程
JDK动态代理 vs CGLIB
面试重点:
面试官:"Spring AOP是如何实现的?JDK动态代理和CGLIB有什么区别?"
JDK动态代理实现:
// 1. 目标接口 public interface UserService { void saveUser(String username); User findUser(Long id); } // 2. 目标实现类 @Service public class UserServiceImpl implements UserService { @Override public void saveUser(String username) { System.out.println("保存用户: " + username); } @Override public User findUser(Long id) { System.out.println("查找用户: " + id); return new User(id, "user" + id); } } // 3. JDK动态代理 public class JdkProxyDemo { public static void main(String[] args) { UserService target = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK代理 - 方法执行前: " + method.getName()); Object result = method.invoke(target, args); System.out.println("JDK代理 - 方法执行后: " + method.getName()); return result; } } ); proxy.saveUser("张三"); } }
CGLIB代理实现:
// 1. 目标类(不需要接口) @Service public class OrderService { public void createOrder(String orderNo) { System.out.println("创建订单: " + orderNo); } } // 2. CGLIB代理 public class CglibProxyDemo { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OrderService.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("CGLIB代理 - 方法执行前: " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("CGLIB代理 - 方法执行后: " + method.getName()); return result; } }); OrderService proxy = (OrderService) enhancer.create(); proxy.createOrder("ORDER001"); } }
两种代理方式对比:
JDK动态代理: ✅ JDK原生支持,无需额外依赖 ✅ 性能较好(方法调用) ❌ 只能代理接口,不能代理类 ❌ 目标类必须实现接口 CGLIB代理: ✅ 可以代理类,不需要接口 ✅ 功能更强大 ❌ 需要额外依赖 ❌ 不能代理final类和final方法 ❌ 性能稍差(字节码生成)
Spring AOP实现原理
切面定义:
@Aspect @Component public class LoggingAspect { // 切点表达式 @Pointcut("execution(* com.example.service.*.*(..))") public void serviceLayer() {} // 前置通知 @Before("serviceLayer()") public void logBefore(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("方法执行前: " + methodName + ", 参数: " + Arrays.toString(args)); } // 后置通知 @After("serviceLayer()") public void logAfter(JoinPoint joinPoint) { System.out.println("方法执行后: " + joinPoint.getSignature().getName()); } // 返回通知 @AfterReturning(pointcut = "serviceLayer()", returning = "result") public void logAfterReturning(JoinPoint joinPoint, Object result) { System.out.println("方法返回: " + joinPoint.getSignature().getName() + ", 结果: " + result); } // 异常通知 @AfterThrowing(pointcut = "serviceLayer()", throwing = "ex") public void logAfterThrowing(JoinPoint joinPoint, Exception ex) { System.out.println("方法异常: " + joinPoint.getSignature().getName() + ", 异常: " + ex.getMessage()); } // 环绕通知 @Around("serviceLayer()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("环绕通知 - 开始: " + joinPoint.getSignature().getName()); try { Object result = joinPoint.proceed(); // 执行目标方法 long endTime = System.currentTimeMillis(); System.out.println("环绕通知 - 结束: " + joinPoint.getSignature().getName() + ", 耗时: " + (endTime - startTime) + "ms"); return result; } catch (Exception ex) { System.out.println("环绕通知 - 异常: " + ex.getMessage()); throw ex; } } }
切点表达式详解:
// 1. execution表达式 @Pointcut("execution(public * com.example.service.*.*(..))") // 修饰符 返回类型 包名.类名.方法名(参数) // 2. within表达式 @Pointcut("within(com.example.service.*)") // 匹配包内的所有方法 // 3. this和target @Pointcut("this(com.example.service.UserService)") // this:代理对象是指定类型 // target:目标对象是指定类型 // 4. args表达式 @Pointcut("args(java.lang.String,..)") // 匹配参数类型 // 5. @annotation表达式 @Pointcut("@annotation(com.example.annotation.Log)") // 匹配有指定注解的方法
事务传播机制
面试重点:
面试官:"Spring事务的传播机制有哪些?什么时候用哪种?"
七种传播机制:
@Service public class TransactionService { // REQUIRED:默认,如果有事务就加入,没有就新建 @Transactional(propagation = Propagation.REQUIRED) public void required() { // 业务逻辑 } // REQUIRES_NEW:总是新建事务,挂起当前事务 @Transactional(propagation = Propagation.REQUIRES_NEW) public void requiresNew() { // 独立事务,不受外部事务影响 } // SUPPORTS:有事务就加入,没有就非事务执行 @Transactional(propagation = Propagation.SUPPORTS) public void supports() { // 支持事务但不强制 } // NOT_SUPPORTED:总是非事务执行,挂起当前事务 @Transactional(propagation = Propagation.NOT_SUPPORTED) public void notSupported() { // 强制非事务执行 } // MANDATORY:必须在事务中执行,否则抛异常 @Transactional(propagation = Propagation.MANDATORY) public void mandatory() { // 必须有事务 } // NEVER:必须非事务执行,有事务就抛异常 @Transactional(propagation = Propagation.NEVER) public void never() { // 绝不能有事务 } // NESTED:嵌套事务,基于Savepoint实现 @Transactional(propagation = Propagation.NESTED) public void nested() { // 嵌套事务,可以独立回滚 } }
实际应用场景:
@Service public class OrderService { @Autowired private PaymentService paymentService; @Autowired private LogService logService; @Transactional public void createOrder(Order order) { // 1. 保存订单 saveOrder(order); // 2. 处理支付(独立事务) paymentService.processPayment(order.getPayment()); // 3. 记录日志(不影响主事务) logService.logOrderCreation(order); } } @Service public class PaymentService { // 支付使用独立事务,失败不影响订单创建 @Transactional(propagation = Propagation.REQUIRES_NEW) public void processPayment(Payment payment) { // 支付逻辑 if (payment.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw new PaymentException("支付金额无效"); } // 调用第三方支付 } } @Service public class LogService { // 日志记录不需要事务 @Transactional(propagation = Propagation.NOT_SUPPORTED) public void logOrderCreation(Order order) { // 记录日志,即使失败也不影响业务 try { // 写入日志 } catch (Exception e) { // 忽略日志异常 } } }
🚀 6.4 Spring MVC请求处理流程
DispatcherServlet工作原理
面试必问:
面试官:"说说Spring MVC的请求处理流程,DispatcherServlet是如何工作的?"
完整流程图:
客户端请求 → DispatcherServlet → HandlerMapping → Handler → HandlerAdapter → Controller → ModelAndView → ViewResolver → View → 响应
源码级别分析:
public class DispatcherServlet extends FrameworkServlet { @Override protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; ModelAndView mv = null; Exception dispatchException = null; try { // 1. 检查是否为文件上传请求 processedRequest = checkMultipart(request); // 2. 根据请求找到对应的Handler mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 3. 根据Handler找到对应的HandlerAdapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 4. 执行拦截器的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 5. 执行Handler(Controller方法) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 6. 设置默认视图名 applyDefaultViewName(processedRequest, mv); // 7. 执行拦截器的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } // 8. 处理结果(渲染视图或处理异常) processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } }
参数解析与数据绑定
参数解析器:
@RestController public class ParameterController { // 1. 路径变量 @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { return userService.findById(id); } // 2. 请求参数 @GetMapping("/users") public List<User> getUsers(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { return userService.findUsers(page, size); } // 3. 请求体 @PostMapping("/users") public User createUser(@RequestBody @Valid User user) { return userService.save(user); } // 4. 请求头 @GetMapping("/info") public String getInfo(@RequestHeader("User-Agent") String userAgent) { return "User-Agent: " + userAgent; } // 5. Cookie @GetMapping("/session") public String getSession(@CookieValue("JSESSIONID") String sessionId) { return "Session ID: " + sessionId; } // 6. 自定义参数解析 @GetMapping("/current-user") public User getCurrentUser(@CurrentUser User user) { return user; } } // 自定义参数解析器 @Component public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CurrentUser.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { // 从请求中解析当前用户 String token = webRequest.getHeader("Authorization"); return parseUserFromToken(token); } private User parseUserFromToken(String token) { // 解析token获取用户信息 return new User(); } }
异常处理机制
全局异常处理:
@ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); // 1. 处理参数校验异常 @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) { List<String> errors = ex.getBindingResult() .getFieldErrors() .stream() .map(error -> error.getField() + ": " + error.getDefaultMessage()) .collect(Collectors.toList()); ErrorResponse errorResponse = new ErrorResponse("参数校验失败", errors); return ResponseEntity.badRequest().body(errorResponse); } // 2. 处理业务异常 @ExceptionHandler(BusinessException.class) public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) { logger.warn("业务异常: {}", ex.getMessage()); ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), ex.getCode()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); } // 3. 处理系统异常 @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResponseEntity<ErrorResponse> handleSystemException(Exception ex) { logger.error("系统异常", ex); ErrorResponse errorResponse = new ErrorResponse("系统内部错误", "SYSTEM_ERROR"); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); } // 4. 处理404异常 @ExceptionHandler(NoHandlerFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ResponseEntity<ErrorResponse> handleNotFoundException(NoHandlerFoundException ex) { ErrorResponse errorResponse = new ErrorResponse("请求的资源不存在", "NOT_FOUND"); return ResponseEntity.notFound().build(); } } // 错误响应实体 public class ErrorResponse { private String message; private String code; private List<String> details; private long timestamp; // 构造器、getter、setter }
💡 京东真题:Spring Boot启动过程分析
面试场景:
面试官:"详细说说Spring Boot应用的启动过程,从main方法开始到容器启动完成"
启动过程分析:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } // 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); } // 构造器 public SpringApplication(Class<?>... primarySources) { this(null, primarySources); } public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 1. 推断应用类型(SERVLET、REACTIVE、NONE) this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 2. 加载ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 3. 加载ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 4. 推断主类 this.mainApplicationClass = deduceMainApplicationClass(); } // 运行方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 5. 设置系统属性 configureHeadlessProperty(); // 6. 获取并启动监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { // 7. 准备环境 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); // 8. 打印Banner Banner printedBanner = printBanner(environment); // 9. 创建ApplicationContext context = createApplicationContext(); // 10. 准备异常报告器 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 11. 准备上下文 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 12. 刷新上下文(核心) refreshContext(context); // 13. 刷新后处理 afterRefresh(context, applicationArguments); stopWatch.stop(); // 14. 发布启动完成事件 listeners.started(context); // 15. 调用ApplicationRunner和CommandLineRunner callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // 16. 发布就绪事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; } }
自动配置原理:
// @SpringBootApplication注解分析 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration // 等价于@Configuration @EnableAutoConfiguration // 启用自动配置 @ComponentScan // 组件扫描 public @interface SpringBootApplication { // ... } // @EnableAutoConfiguration分析 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) // 关键:导入自动配置选择器 public @interface EnableAutoConfiguration { // ... } // AutoConfigurationImportSelector核心逻辑 public class AutoConfigurationImportSelector implements DeferredImportSelector { @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 1. 获取自动配置元数据 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); // 2. 获取自动配置条目 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry( autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { // 3. 加载spring.factories中的自动配置类 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 4. 去重 configurations = removeDuplicates(configurations); // 5. 排除不需要的配置 Set<String> exclusions = getExclusions(annotationMetadata, attributes); configurations.removeAll(exclusions); // 6. 过滤(根据条件注解) configurations = filter(configurations, autoConfigurationMetadata); return new AutoConfigurationEntry(configurations, exclusions); } }
总结
Spring框架是Java生态的核心,掌握其原理对于Java开发者至关重要。面试中Spring相关问题的考察重点:
核心要点:
- IOC容器:Bean生命周期、循环依赖解决、注入方式
- AOP实现:动态代理原理、切面编程、事务管理
- MVC框架:请求处理流程、参数绑定、异常处理
- Boot特性:自动配置、启动过程、新版本特性
面试建议:
- 深入理解底层原理,不要只停留在使用层面
- 结合实际项目经验,展现解决问题的能力
- 关注新版本特性,体现持续学习能力
- 能够对比不同实现方案的优缺点
本章核心要点:
- ✅ Spring Boot 3.0+新特性(GraalVM、WebFlux)
- ✅ IOC容器原理(Bean生命周期、循环依赖)
- ✅ AOP实现机制(动态代理、事务传播)
- ✅ MVC请求处理流程和异常处理
- ✅ Spring Boot启动过程和自动配置原理
下一章预告: MyBatis与数据访问 - 缓存机制、动态SQL、插件原理
#java面试##面试##java速通##秋招投递攻略##秋招笔面试记录#Java面试圣经 文章被收录于专栏
Java面试圣经