Spring面试核心知识点整理
1. Spring单例Bean线程安全性
问题分析
Spring中的单例Bean默认不是线程安全的。当多个线程同时访问同一个单例Bean时,如果Bean中存在可变的成员变量,就会出现线程安全问题。
解决方案
- 无状态设计:避免在Bean中定义可变的成员变量
- ThreadLocal:为每个线程创建独立的变量副本
- 同步机制:使用synchronized、Lock等同步工具
- 原型模式:将Bean的scope设置为prototype
代码示例
@Component
@Scope("prototype") // 每次获取创建新实例
public class UserService {private User currentUser; // 避免这样的可变成员变量
}
2. AOP面向切面编程
核心概念
AOP是将那些与业务无关但对多个对象产生影响的公共行为和逻辑抽取出来,形成可重用的模块,降低系统耦合度。
核心组件
- 切面(Aspect):横切关注点的模块化
- 连接点(JoinPoint):程序执行的某个特定位置
- 切点(Pointcut):定义在哪些连接点上应用通知
- 通知(Advice):在切点执行的代码
- 目标对象(Target):被通知的对象
- 织入(Weaving):将切面应用到目标对象的过程
通知类型
- 前置通知(@Before):目标方法执行前
- 后置通知(@After):目标方法执行后
- 返回通知(@AfterReturning):目标方法正常返回后
- 异常通知(@AfterThrowing):目标方法抛出异常后
- 环绕通知(@Around):包围目标方法执行
实际应用场景
@Aspect
@Component
public class LogAspect {@Around("@annotation(com.example.Log)")public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {// 记录方法执行前的日志long startTime = System.currentTimeMillis();Object result = joinPoint.proceed();long endTime = System.currentTimeMillis();// 记录方法执行后的日志return result;}
}
3. Spring事务管理
事务实现方式
编程式事务
使用TransactionTemplate手动管理事务,代码侵入性强,实际项目中较少使用。
声明式事务
基于AOP实现,通过@Transactional注解声明事务边界,Spring自动处理事务的开启、提交、回滚。
事务失效场景及解决方案
异常捕获导致事务失效
@Transactional
public void updateUser() {try {// 业务逻辑userDao.update();} catch (Exception e) {// 异常被捕获,事务不会回滚log.error("更新失败", e);throw new RuntimeException(e); // 需要重新抛出}
}
检查异常不回滚
// 默认只对RuntimeException和Error回滚
@Transactional(rollbackFor = Exception.class) // 指定所有异常都回滚
public void updateUser() throws Exception {// 业务逻辑
}
非public方法事务失效
Spring AOP基于代理机制,只能拦截public方法。私有方法、protected方法的@Transactional注解无效。
同类方法调用事务失效
@Service
public class UserService {@Transactionalpublic void methodA() {this.methodB(); // 直接调用,绕过代理,事务失效}@Transactionalpublic void methodB() {// 业务逻辑}
}
4. Spring Bean生命周期
完整流程
- BeanDefinition加载:Spring容器解析配置文件,将Bean信息封装成BeanDefinition对象
- 实例化:调用构造函数创建Bean实例
- 属性赋值:进行依赖注入,设置Bean的属性值
- Aware接口处理:如果Bean实现了BeanNameAware、BeanFactoryAware、ApplicationContextAware等接口,Spring会调用相应方法
- 前置处理:BeanPostProcessor的postProcessBeforeInitialization方法
- 初始化:调用InitializingBean的afterPropertiesSet方法或自定义的init-method
- 后置处理:BeanPostProcessor的postProcessAfterInitialization方法
- 使用阶段:Bean可以被应用程序使用
- 销毁:容器关闭时,调用DisposableBean的destroy方法或自定义的destroy-method
关键接口
public class UserService implements BeanNameAware, InitializingBean, DisposableBean {private String beanName;@Overridepublic void setBeanName(String name) {this.beanName = name;}@Overridepublic void afterPropertiesSet() throws Exception {// 初始化逻辑}@Overridepublic void destroy() throws Exception {// 销毁逻辑}
}
5. SpringBoot自动装配原理
核心机制
SpringBoot通过@EnableAutoConfiguration注解启用自动装配,核心原理是SpringFactoriesLoader机制。
工作流程
- 启动类扫描:@SpringBootApplication包含@EnableAutoConfiguration
- 加载配置类:SpringFactoriesLoader读取META-INF/spring.factories文件
- 条件判断:通过@ConditionalOnClass、@ConditionalOnMissingBean等条件注解判断是否需要自动装配
- 配置生效:满足条件的自动配置类被加载到Spring容器
核心注解
- @EnableAutoConfiguration:启用自动装配
- @ConditionalOnClass:当类路径存在指定类时生效
- @ConditionalOnMissingBean:当容器中不存在指定Bean时生效
- @ConfigurationProperties:绑定配置文件属性
自定义自动配置
@Configuration
@ConditionalOnClass(DataSource.class)
@EnableConfigurationProperties(DatabaseProperties.class)
public class DatabaseAutoConfiguration {@Bean@ConditionalOnMissingBeanpublic DataSource dataSource(DatabaseProperties properties) {return new HikariDataSource();}
}