Spring 框架深入解析与面试实战
本文档是Spring框架的全面解析,专为Java开发者深入学习和面试准备而设计。每个知识点都结合了经典面试题和实战案例。
📚 目录
Spring框架概述
什么是Spring框架?
Spring是一个轻量级的Java开发框架,它的核心是控制反转(IoC)和面向切面编程(AOP)。
核心特性
- 轻量级:Spring的基础版本只有2MB左右
- 控制反转:将对象的创建和依赖关系的管理交给Spring容器
- 面向切面编程:将业务逻辑和系统服务分离
- 容器:Spring包含并管理应用对象的配置和生命周期
- 框架:可以将简单的组件配置、组合成为复杂的应用
Spring框架的模块结构
Spring Framework
├── Core Container(核心容器)
│ ├── Beans(Bean管理)
│ ├── Core(核心工具类)
│ ├── Context(上下文)
│ └── Expression Language(表达式语言)
├── Data Access/Integration(数据访问/集成)
│ ├── JDBC(数据库访问)
│ ├── ORM(对象关系映射)
│ ├── OXM(对象XML映射)
│ ├── JMS(Java消息服务)
│ └── Transactions(事务)
├── Web(Web层)
│ ├── WebSocket(WebSocket支持)
│ ├── Servlet(Web MVC)
│ ├── Portlet(Portlet组件)
│ └── Web(Web工具)
├── AOP(面向切面编程)
├── Aspects(集成AspectJ)
├── Instrumentation(设备工具)
└── Test(测试)
🎯 经典面试题
Q1:为什么要使用Spring框架?
答案要点:
- 简化开发:通过IoC容器管理对象,减少代码耦合
- 便于集成:支持各种技术框架的无缝集成
- AOP支持:将日志、事务、安全等横切关注点模块化
- 声明式事务:简化事务管理
- 测试友好:支持单元测试和集成测试
- 生态完善:Spring Boot、Spring Cloud等强大的生态
IoC容器核心原理
什么是IoC(控制反转)?
控制反转是Spring框架的核心思想,它将对象的创建和依赖关系的管理从程序代码中转移到外部容器中。
传统方式 vs IoC方式
// 传统方式:主动创建依赖对象
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 硬编码依赖
public void addUser() {
userDao.save();
}
}
// IoC方式:依赖由容器注入
@Service
public class UserService {
@Autowired
private UserDao userDao; // 容器注入依赖
public void addUser() {
userDao.save();
}
}
Bean的生命周期
Spring Bean的生命经历以下阶段:
- 实例化:创建Bean实例
- 属性赋值:注入依赖属性
- 初始化:
- BeanNameAware:设置Bean名称
- BeanFactoryAware:设置Bean工厂
- ApplicationContextAware:设置应用上下文
- BeanPostProcessor前置处理
- InitializingBean:执行初始化方法
- 自定义init-method
- BeanPostProcessor后置处理
- 使用:Bean可以被使用
- 销毁:
- DisposableBean:执行销毁方法
- 自定义destroy-method
@Component
public class LifeCycleBean implements InitializingBean, DisposableBean {
@PostConstruct
public void postConstruct() {
System.out.println("@PostConstruct执行");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean.afterPropertiesSet()执行");
}
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy执行");
}
@Override
public void destroy() {
System.out.println("DisposableBean.destroy()执行");
}
}
Bean的作用域
| 作用域 | 描述 | 使用场景 |
|---|---|---|
| singleton | 单例模式,容器中只有一个实例 | 默认作用域,无状态Bean |
| prototype | 原型模式,每次请求都创建新实例 | 有状态Bean,需要多实例 |
| request | Web应用中,每个HTTP请求一个实例 | Web层组件 |
| session | Web应用中,每个HTTP Session一个实例 | 用户会话相关组件 |
| application | Web应用中,ServletContext生命周期一个实例 | 应用级共享组件 |
// 单例Bean(默认)
@Service
@Scope("singleton")
public class SingletonService {
// 整个应用只有一个实例
}
// 原型Bean
@Service
@Scope("prototype")
public class PrototypeService {
// 每次注入都是新实例
}
🎯 经典面试题
Q1:Spring Bean是线程安全的吗?
答案要点:
- 单例Bean:默认不是线程安全的,需要开发者自行保证线程安全
- 原型Bean:每个请求都有新实例,不存在线程安全问题
- 线程安全解决方案:
- 使用ThreadLocal存储线程相关数据
- 使用同步关键字synchronized
- 使用不可变对象
- 使用线程安全的集合类(ConcurrentHashMap等)
Q2:Spring如何解决循环依赖?
答案要点:
- 构造器注入:无法解决循环依赖,会抛出异常
- Setter注入:可以解决,通过三级缓存机制
- 字段注入:可以解决,底层也是Setter注入
三级缓存机制:
- 一级缓存:存放完全初始化的Bean
- 二级缓存:存放提前暴露的Bean(半成品)
- 三级缓存:存放Bean工厂,用于生成代理对象
依赖注入详解
依赖注入的三种方式
1. 构造器注入(推荐)
@Service
public class UserService {
private final UserDao userDao;
private final EmailService emailService;
// 构造器注入:强制依赖,不可变对象
public UserService(UserDao userDao, EmailService emailService) {
this.userDao = userDao;
this.emailService = emailService;
}
}
优点:
- 保证依赖不可变(final关键字)
- 保证依赖不为空
- 便于单元测试
- 避免循环依赖
2. Setter注入
@Service
public class UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
优点:
- 可选依赖注入
- 可以在运行时改变依赖
- 适合多态依赖
3. 字段注入
@Service
public class UserService {
@Autowired
private UserDao userDao; // 不推荐,但很常见
}
缺点:
- 违反单一职责原则
- 难以进行单元测试
- 可能导致NullPointerException
自动装配机制
@Autowired注解详解
// 1. 字段注入
@Autowired
private UserService userService;
// 2. Setter注入
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
// 3. 构造器注入(Spring 4.3+可以省略@Autowired)
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
}
多个候选Bean的处理
当有多个相同类型的Bean时,可以使用@Qualifier指定:
@Configuration
public class DataSourceConfig {
@Bean("primaryDataSource")
public DataSource primaryDataSource() {
return new HikariDataSource();
}
@Bean("secondaryDataSource")
public DataSource secondaryDataSource() {
return new HikariDataSource();
}
}
@Service
public class DataService {
@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;
// 或者使用@Resource
@Resource(name = "primaryDataSource")
private DataSource dataSource2;
}
@Conditional条件注入
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "cache.type", havingValue = "redis")
public CacheService redisCacheService() {
return new RedisCacheService();
}
@Bean
@ConditionalOnMissingBean(CacheService.class)
public CacheService defaultCacheService() {
return new MemoryCacheService();
}
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public Jedis jedis() {
return new Jedis();
}
}
🎯 经典面试题
Q1:@Autowired和@Resource的区别?
答案要点:
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring注解 | JDK注解 |
| 装配策略 | 默认byType | 默认byName |
| 支持参数 | @Qualifier | name属性 |
| 用途 | 更灵活 | 更直观 |
Q2:为什么要推荐构造器注入?
答案要点:
- 不可变性:使用final关键字,依赖不可变
- 完整性:对象创建时依赖完整,避免空指针
- 测试友好:便于编写单元测试
- 循环依赖检测:编译期就能发现循环依赖问题
- 代码清晰:明确表达类的必要依赖
AOP面向切面编程
AOP基本概念
AOP(Aspect-Oriented Programming)是一种编程范式,它允许开发者将横切关注点(cross-cutting concerns)模块化。
核心概念
- Aspect(切面):横切关注点的模块化
- Join Point(连接点):程序执行的特定点(如方法调用)
- Advice(通知):在连接点执行的代码
- Pointcut(切点):匹配连接点的表达式
- Target Object(目标对象):被通知的对象
- Proxy(代理):AOP框架创建的对象
- Weaving(织入):将切面应用到目标对象的过程
Advice的类型
@Aspect
@Component
public class LoggingAspect {
// Before通知:方法执行前
@Before("execution(* com.example.service.*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
System.out.println("执行方法:" + joinPoint.getSignature().getName());
}
// After通知:方法执行后(无论成功失败)
@After("execution(* com.example.service.*.*(..))")
public void afterMethod(JoinPoint joinPoint) {
System.out.println("方法执行完成:" + joinPoint.getSignature().getName());
}
// AfterReturning通知:方法成功返回后
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))",
returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("方法返回值:" + result);
}
// AfterThrowing通知:方法抛出异常后
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))",
throwing = "exception")
public void afterThrowing(JoinPoint joinPoint, Exception exception) {
System.out.println("方法异常:" + exception.getMessage());
}
// Around通知:方法执行前后
@Around("execution(* com.example.service.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
try {
Object result = joinPoint.proceed(); // 执行目标方法
long endTime = System.currentTimeMillis();
System.out.println("方法执行时间:" + (endTime - startTime) + "ms");
return result;
} catch (Exception e) {
System.out.println("方法执行异常:" + e.getMessage());
throw e;
}
}
}
切点表达式详解
切点表达式语法
execution(
[修饰符] 返回类型 [包名.类名.]方法名(参数类型) [throws 异常类型]
)
常用切点表达式
// 1. 匹配所有public方法
@Pointcut("execution(public * *(..))")
// 2. 匹配所有以set开头的方法
@Pointcut("execution(* set*(..))")
// 3. 匹配指定包下的所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
// 4. 匹配指定类的所有方法
@Pointcut("execution(* com.example.service.UserService.*(..))")
// 5. 匹配所有返回类型为String的方法
@Pointcut("execution(java.lang.String *(..))")
// 6. 匹配参数为String类型的方法
@Pointcut("execution(* *(java.lang.String, ..))")
// 7. 匹配所有带有@Service注解的类的方法
@Pointcut("@within(org.springframework.stereotype.Service)")
// 8. 匹配所有带有@Transactional注解的方法
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
Spring AOP的实现原理
Spring AOP主要使用两种代理方式:
1. JDK动态代理
// 基于接口的代理
public interface UserService {
void addUser(String name);
}
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
}
// JDK代理只能代理接口
UserService proxy = (UserService) Proxy.newProxyInstance(
UserServiceImpl.class.getClassLoader(),
UserServiceImpl.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置通知");
Object result = method.invoke(target, args);
System.out.println("后置通知");
return result;
}
}
);
2. CGLIB代理
// 基于类的代理(继承目标类)
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置通知");
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置通知");
return result;
}
});
UserServiceImpl proxy = (UserServiceImpl) enhancer.create();
🎯 经典面试题
Q1:Spring AOP和AspectJ有什么区别?
答案要点:
| 特性 | Spring AOP | AspectJ |
|---|---|---|
| 实现方式 | 运行时织入 | 编译时/类加载时织入 |
| 性能 | 运行时反射,性能较低 | 织入时代码生成,性能较高 |
| 功能 | 只支持方法级连接点 | 支持字段、构造器、静态方法等 |
| 复杂度 | 简单易用 | 功能强大但复杂 |
| 集成 | Spring生态无缝集成 | 需要额外编译器 |
Q2:什么时候使用AOP?
答案要点:
- 日志记录:统一的日志输出
- 事务管理:声明式事务
- 权限控制:方法级权限检查
- 性能监控:方法执行时间统计
- 缓存处理:读取缓存、写入缓存
- 异常处理:统一异常处理
- 审计记录:操作记录和追踪
Spring事务管理
事务的基本概念
事务(Transaction)是数据库操作的基本单位,它具有ACID特性:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败
- 一致性(Consistency):事务执行前后,数据库状态保持一致
- 隔离性(Isolation):事务之间互不干扰
- 持久性(Durability):事务提交后,结果永久保存
Spring事务管理的实现方式
1. 编程式事务管理
@Service
public class TransactionalService {
@Autowired
private TransactionTemplate transactionTemplate;
public void transferMoney(String fromAccount, String toAccount, BigDecimal amount) {
transactionTemplate.execute(status -> {
try {
// 转出操作
accountDao.debit(fromAccount, amount);
// 转入操作
accountDao.credit(toAccount, amount);
return "转账成功";
} catch (Exception e) {
status.setRollbackOnly(); // 手动回滚
return "转账失败";
}
});
}
}
2. 声明式事务管理(推荐)
@Service
public class TransactionalService {
@Transactional
public void transferMoney(String fromAccount, String toAccount, BigDecimal amount) {
// 转出操作
accountDao.debit(fromAccount, amount);
// 转入操作
accountDao.credit(toAccount, amount);
}
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
readOnly = false,
rollbackFor = Exception.class)
public void complexOperation() {
// 复杂业务逻辑
}
}
@Transactional注解详解
传播行为(Propagation)
| 传播行为 | 描述 | 使用场景 |
|---|---|---|
| REQUIRED | 如果当前存在事务,则加入;否则创建新事务 | 默认值,大多数场景 |
| REQUIRES_NEW | 创建新事务,挂起当前事务 | 需要独立事务的操作 |
| SUPPORTS | 如果当前存在事务,则加入;否则非事务执行 | 查询操作 |
| NOT_SUPPORTED | 非事务执行,挂起当前事务 | 不需要事务的操作 |
| NEVER | 非事务执行,如果存在事务抛出异常 | 强制非事务操作 |
| MANDATORY | 必须在事务中执行,否则抛出异常 | 必须有事务的操作 |
| NESTED | 嵌套事务,部分回滚 | 需要部分回滚的场景 |
隔离级别(Isolation)
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 描述 |
|---|---|---|---|---|
| DEFAULT | 取决于数据库 | 取决于数据库 | 取决于数据库 | 使用数据库默认隔离级别 |
| READ_UNCOMMITTED | 可能 | 可能 | 可能 | 最低隔离级别,性能最好 |
| READ_COMMITTED | 不可能 | 可能 | 可能 | 避免脏读,大多数数据库默认 |
| REPEATABLE_READ | 不可能 | 不可能 | 可能 | 避免脏读和不可重复读 |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 | 最高隔离级别,避免所有并发问题 |
// 示例:银行转账事务
@Service
public class BankService {
@Transactional(propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
rollbackFor = {BankException.class, RuntimeException.class})
public void transfer(Long fromId, Long toId, BigDecimal amount) {
// 检查余额
BigDecimal fromBalance = accountDao.getBalance(fromId);
if (fromBalance.compareTo(amount) < 0) {
throw new InsufficientBalanceException("余额不足");
}
// 扣款
accountDao.debit(fromId, amount);
// 存款
accountDao.credit(toId, amount);
// 记录交易日志
transactionLogDao.logTransfer(fromId, toId, amount);
}
}
事务失效的场景
1. 方法访问权限问题
@Service
public class TransactionService {
// ❌ 错误:private方法无法被AOP代理
@Transactional
private void privateMethod() {
// 业务逻辑
}
// ✅ 正确:public方法
@Transactional
public void publicMethod() {
// 业务逻辑
}
}
2. 方法内部调用
@Service
public class TransactionService {
// ❌ 错误:内部调用不会触发事务
public void method1() {
method2(); // 直接调用,不会经过AOP代理
}
@Transactional
public void method2() {
// 业务逻辑
}
// ✅ 正确:通过注入自身调用
@Autowired
private TransactionService self;
public void method1() {
self.method2(); // 通过AOP代理调用
}
}
3. 异常类型不匹配
@Service
public class TransactionService {
// ❌ 错误:默认只回滚RuntimeException和Error
@Transactional
public void method1() throws IOException {
// 抛出检查异常不会触发回滚
throw new IOException("文件操作失败");
}
// ✅ 正确:指定回滚异常类型
@Transactional(rollbackFor = IOException.class)
public void method2() throws IOException {
throw new IOException("文件操作失败");
}
}
🎯 经典面试题
Q1:Spring事务在什么情况下会失效?
答案要点:
- 方法不是public:AOP只能代理public方法
- 自调用问题:类内部方法调用不经过代理
- 异常类型不匹配:检查异常默认不回滚
- 数据库引擎不支持:如MyISAM不支持事务
- 传播行为设置错误:如NEVER、NOT_SUPPORTED等
- 事务注解被覆盖:类级别和方法级别冲突
Q2:Spring事务的传播行为有哪些,分别是什么意思?
答案要点: 详细解释7种传播行为,特别是:
- REQUIRED:默认行为,支持当前事务,没有则创建
- REQUIRES_NEW:总是创建新事务,挂起当前事务
- NESTED:嵌套事务,可以部分回滚
- MANDATORY:必须存在事务,否则抛出异常
Spring事件机制
Spring事件体系概述
Spring事件机制是基于观察者模式的实现,它实现了ApplicationEventPublisher和ApplicationListener接口,允许组件之间进行松耦合的通信。
核心组件
- ApplicationEvent:事件基类,所有自定义事件都需要继承它
- ApplicationListener:事件监听器接口
- ApplicationEventPublisher:事件发布器接口
- ApplicationEventMulticaster:事件广播器,负责事件分发
自定义事件和监听器
1. 定义自定义事件
// 用户注册事件
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
private final String email;
private final LocalDateTime registrationTime;
public UserRegisteredEvent(Object source, String username, String email) {
super(source);
this.username = username;
this.email = email;
this.registrationTime = LocalDateTime.now();
}
// getters
public String getUsername() { return username; }
public String getEmail() { return email; }
public LocalDateTime getRegistrationTime() { return registrationTime; }
}
// 订单创建事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Long orderId;
private final String userId;
private final BigDecimal amount;
private final List<String> items;
public OrderCreatedEvent(Object source, Long orderId, String userId,
BigDecimal amount, List<String> items) {
super(source);
this.orderId = orderId;
this.userId = userId;
this.amount = amount;
this.items = new ArrayList<>(items);
}
// getters
public Long getOrderId() { return orderId; }
public String getUserId() { return userId; }
public BigDecimal getAmount() { return amount; }
public List<String> getItems() { return new ArrayList<>(items); }
}
2. 实现事件监听器
@Component
public class UserEventListener {
private static final Logger logger = LoggerFactory.getLogger(UserEventListener.class);
// 方式一:实现ApplicationListener接口
@Component
public static class UserRegistrationListener implements ApplicationListener<UserRegisteredEvent> {
@Autowired
private EmailService emailService;
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
logger.info("用户注册事件处理:{}", event.getUsername());
// 发送欢迎邮件
emailService.sendWelcomeEmail(event.getEmail(), event.getUsername());
// 记录注册日志
logger.info("用户 {} 于 {} 注册成功",
event.getUsername(), event.getRegistrationTime());
}
}
// 方式二:使用@EventListener注解(推荐)
@EventListener
public void handleUserRegistration(UserRegisteredEvent event) {
logger.info("处理用户注册事件:{}", event.getUsername());
// 发送优惠券
couponService.sendWelcomeCoupon(event.getUsername());
}
// 异步事件处理
@EventListener
@Async("taskExecutor")
public void handleUserRegistrationAsync(UserRegisteredEvent event) {
logger.info("异步处理用户注册事件:{}", event.getUsername());
// 记录到大数据平台
analyticsService.recordUserRegistration(event);
}
// 条件事件处理
@EventListener(condition = "#event.username.startsWith('vip')")
public void handleVipUserRegistration(UserRegisteredEvent event) {
logger.info("处理VIP用户注册:{}", event.getUsername());
// VIP用户特殊处理
vipService.upgradeToVip(event.getUsername());
}
// 处理多个事件
@EventListener({UserRegisteredEvent.class, OrderCreatedEvent.class})
public void handleUserAndOrderEvents(ApplicationEvent event) {
if (event instanceof UserRegisteredEvent) {
handleUserRegistration((UserRegisteredEvent) event);
} else if (event instanceof OrderCreatedEvent) {
handleOrderCreated((OrderCreatedEvent) event);
}
}
}
3. 发布事件
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public User registerUser(String username, String email, String password) {
// 创建用户
User user = new User();
user.setUsername(username);
user.setEmail(email);
user.setPassword(passwordEncoder.encode(password));
user.setRegistrationTime(LocalDateTime.now());
// 保存用户
User savedUser = userRepository.save(user);
// 发布用户注册事件
UserRegisteredEvent event = new UserRegisteredEvent(this, username, email);
eventPublisher.publishEvent(event);
logger.info("用户注册成功,已发布注册事件:{}", username);
return savedUser;
}
}
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public Order createOrder(String userId, List<OrderItem> items) {
// 计算订单金额
BigDecimal totalAmount = items.stream()
.map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 创建订单
Order order = new Order();
order.setUserId(userId);
order.setItems(items);
order.setTotalAmount(totalAmount);
order.setOrderTime(LocalDateTime.now());
order.setStatus("CREATED");
Order savedOrder = orderRepository.save(order);
// 发布订单创建事件
OrderCreatedEvent event = new OrderCreatedEvent(
this, savedOrder.getId(), userId, totalAmount,
items.stream().map(OrderItem::getProductName).collect(Collectors.toList())
);
eventPublisher.publishEvent(event);
logger.info("订单创建成功,已发布创建事件:{}", savedOrder.getId());
return savedOrder;
}
}
事务事件
@TransactionalEventListener
Spring 4.2+提供了事务事件监听器,可以在事务的不同阶段处理事件。
@Component
public class TransactionalEventListeners {
// 事务提交后执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(UserRegisteredEvent event) {
logger.info("事务提交后处理:{}", event.getUsername());
// 发送邮件(只有事务成功提交才发送)
emailService.sendWelcomeEmail(event.getEmail(), event.getUsername());
}
// 事务提交前执行
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleBeforeCommit(UserRegisteredEvent event) {
logger.info("事务提交前处理:{}", event.getUsername());
// 预分配资源
resourceService.allocateResources(event.getUsername());
}
// 事务回滚后执行
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(UserRegisteredEvent event) {
logger.info("事务回滚后处理:{}", event.getUsername());
// 清理资源
resourceService.cleanupResources(event.getUsername());
}
// 事务完成后执行(无论成功或失败)
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void handleAfterCompletion(UserRegisteredEvent event) {
logger.info("事务完成后处理:{}", event.getUsername());
// 记录日志
auditService.logRegistrationAttempt(event.getUsername());
}
}
事件异常处理
事件传播和异常处理机制
@Component
public class EventErrorHandler {
// 处理事件处理过程中的异常
@EventListener
public void handleEventProcessingError(ApplicationEvent event) {
try {
// 处理事件逻辑
processEvent(event);
} catch (Exception e) {
logger.error("事件处理失败:{}", event.getClass().getSimpleName(), e);
// 记录失败事件到重试队列
retryQueueService.addFailedEvent(event);
}
}
// 使用@EventListener的异常处理
@EventListener
public void handleUserRegistrationWithRetry(UserRegisteredEvent event) {
int maxRetries = 3;
int retryCount = 0;
while (retryCount < maxRetries) {
try {
// 发送欢迎短信
smsService.sendWelcomeSms(event.getPhoneNumber(), event.getUsername());
break;
} catch (Exception e) {
retryCount++;
if (retryCount >= maxRetries) {
logger.error("短信发送失败,已达到最大重试次数:{}", event.getUsername(), e);
// 发送告警
alertService.sendAlert("短信发送失败", event.getUsername());
} else {
logger.warn("短信发送失败,准备重试:{},第{}次", event.getUsername(), retryCount);
try {
Thread.sleep(1000 * retryCount); // 指数退避
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
break;
}
}
}
}
}
}
事件性能优化
异步事件处理
@Configuration
@EnableAsync
public class EventAsyncConfig {
@Bean("eventTaskExecutor")
public ThreadPoolTaskExecutor eventTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("event-async-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
return executor;
}
@Bean("transactionEventTaskExecutor")
public ThreadPoolTaskExecutor transactionEventTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("transaction-event-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
return executor;
}
}
// 使用异步事件
@Component
public class AsyncEventProcessor {
@Async("eventTaskExecutor")
@EventListener
public void handleAsyncEvent(UserRegisteredEvent event) {
// 异步处理耗时操作
analyticsService.processUserData(event);
recommendationService.buildUserProfile(event);
}
@Async("transactionEventTaskExecutor")
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAsyncTransactionEvent(OrderCreatedEvent event) {
// 异步处理事务后操作
inventoryService.updateInventory(event.getItems());
notificationService.sendOrderConfirmation(event.getUserId(), event.getOrderId());
}
}
🎯 经典面试题
Q1:Spring事件机制的优势是什么?
答案要点:
- 松耦合:发布者和监听器之间没有直接依赖
- 扩展性强:可以轻松添加新的监听器
- 异步处理:支持异步事件处理,提高性能
- 事务支持:提供事务事件监听器
- 类型安全:基于强类型的事件系统
Q2:@EventListener和实现ApplicationListener接口有什么区别?
答案要点:
| 特性 | ApplicationListener接口 | @EventListener注解 |
|---|---|---|
| 声明方式 | 实现接口 | 方法级注解 |
| 灵活性 | 一个类监听一种事件 | 一个方法监听多种事件 |
| 条件过滤 | 需要在方法内判断 | 支持SpEL表达式 |
| 异步支持 | 需要额外配置 | 支持@Async注解 |
| 参数绑定 | 只能传入事件对象 | 支持参数解析 |
Q3:Spring事件和MQ消息有什么区别?
答案要点:
| 特性 | Spring事件 | MQ消息 |
|---|---|---|
| 作用范围 | 单个应用内 | 跨应用、跨服务 |
| 可靠性 | 内存中,应用重启丢失 | 持久化,可靠性高 |
| 性能 | 高性能,内存操作 | 网络IO,性能相对较低 |
| 复杂度 | 简单易用 | 需要MQ中间件 |
| 扩展性 | 单机水平扩展有限 | 分布式扩展 |
| 适用场景 | 应用内解耦 | 系统间解耦 |
Spring条件装配和配置
@Conditional注解家族
Spring 4.0+引入了强大的条件装配机制,通过@Conditional注解可以根据特定条件决定是否创建Bean。
基础条件注解
@Configuration
public class ConditionalConfig {
// 1. @ConditionalOnClass:当类路径中存在指定类时创建Bean
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisService jedisRedisService() {
return new JedisRedisService();
}
@Bean
@ConditionalOnMissingClass("redis.clients.jedis.Jedis")
public RedisService mockRedisService() {
return new MockRedisService();
}
// 2. @ConditionalOnBean:当容器中存在指定Bean时创建
@Bean
@ConditionalOnBean(DataSource.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 3. @ConditionalOnMissingBean:当容器中不存在指定Bean时创建
@Bean
@ConditionalOnMissingBean(CacheManager.class)
public CacheManager simpleCacheManager() {
return new ConcurrentMapCacheManager("users", "products");
}
// 4. @ConditionalOnProperty:根据配置属性决定
@Bean
@ConditionalOnProperty(name = "cache.type", havingValue = "redis", matchIfMissing = false)
public CacheService redisCacheService() {
return new RedisCacheService();
}
@Bean
@ConditionalOnProperty(name = "cache.type", havingValue = "memory", matchIfMissing = true)
public CacheService memoryCacheService() {
return new MemoryCacheService();
}
// 5. @ConditionalOnExpression:基于SpEL表达式
@Bean
@ConditionalOnExpression("${app.feature.enabled:false} and '${app.env}'.equals('prod')")
public ProductionService productionService() {
return new ProductionService();
}
// 6. @ConditionalOnWebApplication:在Web环境中创建
@Bean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
// 自定义配置
};
}
// 7. @ConditionalOnNotWebApplication:在非Web环境中创建
@Bean
@ConditionalOnNotWebApplication
public CommandLineRunner commandLineRunner() {
return args -> {
System.out.println("应用启动,非Web环境");
};
}
// 8. @ConditionalOnJava:基于Java版本
@Bean
@ConditionalOnJava(JavaVersion.EIGHT)
public Java8Feature java8Feature() {
return new Java8Feature();
}
@Bean
@ConditionalOnJava(JavaVersion.ELEVEN)
public Java11Feature java11Feature() {
return new Java11Feature();
}
}
自定义条件注解
// 1. 自定义条件接口
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取注解属性
Map<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnSystemProperty.class.getName());
String propertyName = (String) attributes.get("name");
String havingValue = (String) attributes.get("havingValue");
boolean matchIfMissing = (Boolean) attributes.get("matchIfMissing");
// 获取系统属性
String propertyValue = System.getProperty(propertyName);
if (propertyValue == null) {
return matchIfMissing;
}
if (havingValue.isEmpty()) {
return true; // 只要求属性存在
}
return havingValue.equals(propertyValue);
}
}
// 2. 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
String name();
String havingValue() default "";
boolean matchIfMissing() default false;
}
// 3. 使用自定义条件注解
@Configuration
public class CustomConditionalConfig {
@Bean
@ConditionalOnSystemProperty(name = "os.name", havingValue = "Windows 10")
public WindowsService windowsService() {
return new WindowsService();
}
@Bean
@ConditionalOnSystemProperty(name = "java.vm.vendor", havingValue = "Oracle Corporation")
public OracleJdkService oracleJdkService() {
return new OracleJdkService();
}
@Bean
@ConditionalOnSystemProperty(name = "app.env", matchIfMissing = true)
public DefaultEnvironmentService defaultEnvironmentService() {
return new DefaultEnvironmentService();
}
}
Profile环境配置
Profile注解使用
@Configuration
public class ProfileConfig {
// 开发环境配置
@Bean
@Profile("dev")
public DataSource devDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:h2:mem:devdb");
dataSource.setUsername("dev");
dataSource.setPassword("dev");
return dataSource;
}
// 测试环境配置
@Bean
@Profile("test")
public DataSource testDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:h2:mem:testdb");
dataSource.setUsername("test");
dataSource.setPassword("test");
return dataSource;
}
// 生产环境配置
@Bean
@Profile("prod")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource prodDataSource() {
return DataSourceBuilder.create().build();
}
// 多个环境
@Bean
@Profile({"dev", "test"})
public MockEmailService mockEmailService() {
return new MockEmailService();
}
@Bean
@Profile("prod")
public SmtpEmailService smtpEmailService() {
return new SmtpEmailService();
}
// 非特定环境
@Bean
@Profile("!prod")
public DebugService debugService() {
return new DebugService();
}
}
Profile激活方式
// 1. 通过SpringApplication激活
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setAdditionalProfiles("dev", "debug");
app.run(args);
}
}
// 2. 通过配置文件激活
// application.yml
spring:
profiles:
active: dev
// 3. 通过环境变量激活
// SPRING_PROFILES_ACTIVE=prod
// 4. 通过JVM参数激活
// -Dspring.profiles.active=dev
// 5. 通过命令行参数激活
// java -jar app.jar --spring.profiles.active=prod
Profile配置文件
# application.yml - 默认配置
spring:
application:
name: my-app
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
---
# application-dev.yml - 开发环境
spring:
profiles: dev
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: dev_user
password: dev_pass
jpa:
show-sql: true
hibernate:
ddl-auto: create-drop
logging:
level:
com.example: DEBUG
---
# application-test.yml - 测试环境
spring:
profiles: test
datasource:
url: jdbc:h2:mem:testdb
username: sa
password:
jpa:
show-sql: false
hibernate:
ddl-auto: create-drop
logging:
level:
com.example: INFO
---
# application-prod.yml - 生产环境
spring:
profiles: prod
datasource:
url: jdbc:mysql://prod-db-host:3306/prod_db
username: ${DB_USERNAME:prod_user}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
minimum-idle: 5
jpa:
show-sql: false
hibernate:
ddl-auto: validate
logging:
level:
com.example: WARN
file:
name: /var/log/my-app/application.log
@Import和@ImportResource
@Import注解使用
// 1. 导入配置类
@Configuration
@Import({DatabaseConfig.class, SecurityConfig.class, WebConfig.class})
public class AppConfig {
// 主配置
}
// 2. 导入普通Bean类
@Configuration
@Import({UserService.class, OrderService.class})
public class ServiceConfig {
// 配置其他服务
}
// 3. 使用ImportSelector动态导入
public class FeatureImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(
EnableFeature.class.getName());
FeatureType[] features = (FeatureType[]) attributes.get("features");
List<String> configurations = new ArrayList<>();
for (FeatureType feature : features) {
switch (feature) {
case CACHE:
configurations.add(CacheConfiguration.class.getName());
break;
case SCHEDULED:
configurations.add(ScheduledConfiguration.class.getName());
break;
case ASYNC:
configurations.add(AsyncConfiguration.class.getName());
break;
case SECURITY:
configurations.add(SecurityConfiguration.class.getName());
break;
}
}
return configurations.toArray(new String[0]);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(FeatureImportSelector.class)
public @interface EnableFeature {
FeatureType[] value() default {};
}
// 使用自定义导入注解
@Configuration
@EnableFeature({FeatureType.CACHE, FeatureType.ASYNC})
public class DynamicConfig {
// 动态导入配置
}
// 4. 使用ImportBeanDefinitionRegistrar
public class CustomImportRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 动态注册Bean定义
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(CustomBean.class);
builder.addPropertyValue("name", "Dynamic Bean");
registry.registerBeanDefinition("customBean", builder.getBeanDefinition());
}
}
@Configuration
@Import(CustomImportRegistrar.class)
public class RegistrarConfig {
// 通过Registrar注册Bean
}
@ImportResource导入XML配置
@Configuration
@ImportResource({"classpath:spring-database.xml", "classpath:spring-security.xml"})
public class XmlConfig {
// 混合JavaConfig和XML配置
}
// XML配置文件示例
<!-- spring-database.xml -->
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
</beans>
属性配置和绑定
@ConfigurationProperties详解
// 1. 基础属性绑定
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private String version;
private String description;
private boolean enabled = true;
// setters and getters
}
// 2. 嵌套属性绑定
@Component
@ConfigurationProperties(prefix = "app")
public class AdvancedAppProperties {
private String name;
private final Security security = new Security();
private final Cache cache = new Cache();
private final List<String> modules = new ArrayList<>();
private final Map<String, String> settings = new HashMap<>();
// getters and setters
public static class Security {
private boolean enabled = true;
private String secretKey;
private int tokenExpiration = 3600;
private final List<String> allowedOrigins = new ArrayList<>();
// getters and setters
}
public static class Cache {
private String type = "memory";
private int ttl = 3600;
private int maxSize = 1000;
private final Redis redis = new Redis();
// getters and setters
public static class Redis {
private String host = "localhost";
private int port = 6379;
private String password;
private int database = 0;
// getters and setters
}
}
}
// 3. 验证属性
@Component
@ConfigurationProperties(prefix = "app.database")
@Validated
public class DatabaseProperties {
@NotBlank
private String url;
@NotBlank
private String username;
private String password;
@Min(1)
@Max(100)
private int maxConnections = 10;
@Min(1000)
@Max(300000)
private int connectionTimeout = 30000;
// getters and setters
}
// 4. 启用配置属性
@Configuration
@EnableConfigurationProperties({AppProperties.class, DatabaseProperties.class})
public class PropertyConfig {
// 配置类
}
属性文件配置
# application.yml
app:
name: My Spring Application
version: 1.0.0
description: A comprehensive Spring application
enabled: true
security:
enabled: true
secret-key: mySecretKey123
token-expiration: 7200
allowed-origins:
- http://localhost:3000
- https://app.example.com
cache:
type: redis
ttl: 1800
max-size: 5000
redis:
host: redis.example.com
port: 6379
password: ${REDIS_PASSWORD}
database: 1
modules:
- user-management
- order-processing
- notification-service
- analytics
settings:
theme: light
language: zh-CN
timezone: Asia/Shanghai
debug: false
app:
database:
url: jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=UTC
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD}
max-connections: 20
connection-timeout: 15000
属性占位符和SpEL表达式
@Configuration
public class PlaceholderConfig {
// 1. 基础占位符使用
@Value("${app.name}")
private String appName;
@Value("${app.version:1.0.0}") // 默认值
private String appVersion;
@Value("#{systemProperties['java.home']}") // 系统属性
private String javaHome;
@Value("#{systemEnvironment['JAVA_HOME']}") // 环境变量
private String javaHomeEnv;
// 2. SpEL表达式
@Value("#{app.name + ' v' + app.version}")
private String fullAppName;
@Value("#{'${app.modules}'.split(',')}")
private List<String> modules;
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomValue;
@Value("#{new java.text.SimpleDateFormat('yyyy-MM-dd').format(new java.util.Date())}")
private String currentDate;
// 3. 条件表达式
@Value("#{app.security.enabled ? 'security-enabled' : 'security-disabled'}")
private String securityStatus;
@Value("#{app.cache.type == 'redis' ? 'Redis cache' : 'Memory cache'}")
private String cacheDescription;
// 4. 复杂SpEL表达式
@Bean
public DataSource dataSource(
@Value("${app.database.url}") String url,
@Value("${app.database.username}") String username,
@Value("${app.database.password}") String password) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(username);
config.setPassword(password);
// 使用SpEL表达式配置连接池
config.setMaximumPoolSize(
appCache.getProperties().get("max-connections") != null ?
Integer.parseInt(appCache.getProperties().get("max-connections").toString()) : 10
);
return new HikariDataSource(config);
}
}
🎯 经典面试题
Q1:@Conditional和@Profile有什么区别?
答案要点:
| 特性 | @Conditional | @Profile |
|---|---|---|
| 条件类型 | 基于任意条件 | 基于环境Profile |
| 灵活性 | 高,可自定义条件 | 低,仅环境判断 |
| 复杂度 | 复杂,需要实现Condition接口 | 简单,注解使用 |
| 用途 | 细粒度条件控制 | 环境相关配置 |
| 组合性 | 支持多个条件组合 | 不支持复杂组合 |
Q2:Spring Boot自动配置的原理是什么?
答案要点:
- @EnableAutoConfiguration:启用自动配置
- spring.factories文件:定义自动配置类
- @Conditional注解:条件装配
- 配置属性绑定:@ConfigurationProperties
- 优先级机制:用户配置 > 自动配置
Q3:如何自定义Spring的条件注解?
答案要点:
- 实现Condition接口:定义匹配逻辑
- 创建注解:使用@Conditional元注解
- 获取环境信息:通过ConditionContext
- 读取注解属性:通过AnnotatedTypeMetadata
- 返回匹配结果:boolean决定是否装配
Q4:@ConfigurationProperties和@Value有什么区别?
答案要点:
| 特性 | @ConfigurationProperties | @Value |
|---|---|---|
| 绑定方式 | 批量属性绑定 | 单个属性绑定 |
| 类型安全 | 强类型,支持嵌套对象 | 字符串类型,需要转换 |
| 支持验证 | 支持@Validated | 不支持验证 |
| SpEL支持 | 不支持SpEL表达式 | 支持SpEL表达式 |
| 用途 | 复杂配置对象 | 简单配置值 |
| IDE支持 | 良好的IDE提示 | 有限的IDE提示 |
Spring环境抽象和属性管理
Environment抽象概念
Spring的Environment抽象是一个高级接口,用于管理应用程序的环境配置,包括profiles和properties。
核心接口层次
Environment (接口)
├── ConfigurableEnvironment (可配置环境)
│ ├── ConfigurableWebEnvironment (Web环境)
│ ├── AbstractEnvironment (抽象实现)
│ │ ├── StandardEnvironment (标准环境)
│ │ └── StandardServletEnvironment (Servlet环境)
│ └── MockEnvironment (测试环境)
Environment接口详解
@Component
public class EnvironmentExample {
@Autowired
private Environment environment;
public void demonstrateEnvironment() {
// 1. 获取激活的Profiles
String[] activeProfiles = environment.getActiveProfiles();
System.out.println("激活的Profiles: " + Arrays.toString(activeProfiles));
// 2. 获取默认的Profiles
String[] defaultProfiles = environment.getDefaultProfiles();
System.out.println("默认的Profiles: " + Arrays.toString(defaultProfiles));
// 3. 检查是否包含指定Profile
boolean devActive = environment.acceptsProfiles(Profiles.of("dev"));
boolean prodActive = environment.acceptsProfiles(Profiles.of("prod"));
System.out.println("开发环境激活: " + devActive);
System.out.println("生产环境激活: " + prodActive);
// 4. 获取系统属性
String javaHome = environment.getProperty("java.home");
String osName = environment.getProperty("os.name");
System.out.println("Java Home: " + javaHome);
System.out.println("OS Name: " + osName);
// 5. 获取配置属性
String appName = environment.getProperty("app.name");
Integer serverPort = environment.getProperty("server.port", Integer.class, 8080);
System.out.println("应用名称: " + appName);
System.out.println("服务器端口: " + serverPort);
// 6. 获取必需的属性(如果不存在会抛异常)
String dbUrl = environment.getRequiredProperty("spring.datasource.url");
// 7. 检查属性是否存在
boolean hasCacheEnabled = environment.containsProperty("cache.enabled");
System.out.println("缓存启用属性存在: " + hasCacheEnabled);
// 8. 解析占位符
String resolvedUrl = environment.resolvePlaceholders("${database.url}");
System.out.println("解析后的URL: " + resolvedUrl);
// 9. 获取系统环境变量
String path = environment.getProperty("PATH");
String javaHomeEnv = environment.getProperty("JAVA_HOME");
System.out.println("PATH: " + path);
System.out.println("JAVA_HOME: " + javaHomeEnv);
}
}
属性源(PropertySource)管理
@Configuration
public class PropertySourceConfig {
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@PostConstruct
public void demonstratePropertySources() {
ConfigurableEnvironment env = getEnvironment();
// 1. 获取所有属性源
MutablePropertySources propertySources = env.getPropertySources();
System.out.println("=== 属性源列表 ===");
for (PropertySource<?> ps : propertySources) {
System.out.println(String.format("名称: %s, 类型: %s, 优先级: %d",
ps.getName(), ps.getClass().getSimpleName(), propertySources.precedenceOf(ps)));
}
// 2. 添加自定义属性源
Map<String, Object> customProperties = new HashMap<>();
customProperties.put("custom.app.name", "Custom Application");
customProperties.put("custom.app.version", "2.0.0");
PropertySource<?> customPropertySource = new MapPropertySource("customProperties", customProperties);
propertySources.addFirst(customPropertySource); // 最高优先级
// 3. 添加文件属性源
try {
Resource resource = new ClassPathResource("custom-config.properties");
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
PropertySource<?> filePropertySource = new PropertiesPropertySource("fileProperties", properties);
propertySources.addAfter("customProperties", filePropertySource);
} catch (IOException e) {
e.printStackTrace();
}
// 4. 环境特定的属性源
if (env.acceptsProfiles(Profiles.of("dev"))) {
Map<String, Object> devProperties = new HashMap<>();
devProperties.put("dev.debug", true);
devProperties.put("dev.show-sql", true);
PropertySource<?> devPropertySource = new MapPropertySource("devProperties", devProperties);
propertySources.addBefore("configurationProperties", devPropertySource);
}
// 5. 动态属性源
ReloadablePropertySource dynamicPropertySource = new ReloadablePropertySource("dynamicProperties");
propertySources.addLast(dynamicPropertySource); // 最低优先级
}
}
// 可重载的属性源
public class ReloadablePropertySource extends PropertySource<Object> {
private final Map<String, Object> properties = new ConcurrentHashMap<>();
public ReloadablePropertySource(String name) {
super(name);
loadProperties();
}
private void loadProperties() {
// 从数据库、配置中心等动态加载属性
properties.put("dynamic.config.value", "Dynamic Value: " + System.currentTimeMillis());
properties.put("dynamic.feature.enabled", Math.random() > 0.5);
}
public void reload() {
properties.clear();
loadProperties();
}
@Override
public Object getProperty(String name) {
return properties.get(name);
}
@Override
public boolean containsProperty(String name) {
return properties.containsKey(name);
}
@Override
public String[] getPropertyNames() {
return properties.keySet().toArray(new String[0]);
}
}
ApplicationContext与Environment集成
不同ApplicationContext的Environment
@Configuration
public class ApplicationContextEnvironmentConfig {
// 1. AnnotationConfigApplicationContext
@Bean
public ApplicationContext demonstrateAnnotationConfigContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();
environment.setActiveProfiles("dev");
// 设置默认Profile
environment.setDefaultProfiles("default");
// 添加配置类
context.register(AppConfig.class);
context.refresh();
return context;
}
// 2. GenericApplicationContext
@Bean
public ApplicationContext demonstrateGenericContext() {
GenericApplicationContext context = new GenericApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
// 添加自定义属性源
propertySources.addFirst(new SystemEnvironmentPropertySource("systemEnv", System.getenv()));
// 注册Bean定义
context.registerBeanDefinition("configService",
BeanDefinitionBuilder.rootBeanDefinition(ConfigService.class).getBeanDefinition());
context.refresh();
return context;
}
// 3. 动态设置Profiles
@Bean
public void demonstrateDynamicProfiles() {
GenericApplicationContext context = new GenericApplicationContext();
ConfigurableEnvironment environment = context.getEnvironment();
// 动态添加Active Profile
environment.addActiveProfile("development");
environment.addActiveProfile("debug");
// 条件化设置Profile
if (System.getProperty("os.name").contains("Windows")) {
environment.addActiveProfile("windows");
} else if (System.getProperty("os.name").contains("Linux")) {
environment.addActiveProfile("linux");
}
// 检查Profile组合
boolean devWithDebug = environment.acceptsProfiles(
Profiles.of("dev & debug"));
boolean prodOrTest = environment.acceptsProfiles(
Profiles.of("prod | test"));
boolean notProd = environment.acceptsProfiles(
Profiles.of("!prod"));
System.out.println("开发+调试环境: " + devWithDebug);
System.out.println("生产或测试环境: " + prodOrTest);
System.out.println("非生产环境: " + notProd);
}
}
多环境配置管理
环境特定的配置加载
@Configuration
public class MultiEnvironmentConfig {
@Bean
@ConfigurationProperties(prefix = "app")
public AppProperties appProperties(Environment environment) {
AppProperties properties = new AppProperties();
// 根据环境加载不同配置
if (environment.acceptsProfiles(Profiles.of("dev"))) {
properties.setName("Development Application");
properties.setDebug(true);
properties.setLogLevel("DEBUG");
} else if (environment.acceptsProfiles(Profiles.of("test"))) {
properties.setName("Test Application");
properties.setDebug(true);
properties.setLogLevel("INFO");
} else if (environment.acceptsProfiles(Profiles.of("prod"))) {
properties.setName("Production Application");
properties.setDebug(false);
properties.setLogLevel("WARN");
} else {
properties.setName("Default Application");
properties.setDebug(false);
properties.setLogLevel("INFO");
}
return properties;
}
@Bean
public DataSource dataSource(Environment environment) {
HikariConfig config = new HikariConfig();
// 根据环境配置数据源
if (environment.acceptsProfiles(Profiles.of("dev"))) {
config.setJdbcUrl("jdbc:h2:mem:devdb");
config.setUsername("sa");
config.setPassword("");
config.setMaximumPoolSize(5);
} else if (environment.acceptsProfiles(Profiles.of("test"))) {
config.setJdbcUrl("jdbc:h2:mem:testdb");
config.setUsername("test");
config.setPassword("test");
config.setMaximumPoolSize(3);
} else if (environment.acceptsProfiles(Profiles.of("prod"))) {
config.setJdbcUrl(environment.getRequiredProperty("prod.database.url"));
config.setUsername(environment.getRequiredProperty("prod.database.username"));
config.setPassword(environment.getRequiredProperty("prod.database.password"));
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
}
return new HikariDataSource(config);
}
@Bean
public CacheManager cacheManager(Environment environment) {
if (environment.acceptsProfiles(Profiles.of("dev"))) {
// 开发环境使用内存缓存
return new ConcurrentMapCacheManager("users", "products");
} else if (environment.acceptsProfiles(Profiles.of("test"))) {
// 测试环境使用禁用缓存
return new NoOpCacheManager();
} else {
// 生产环境使用Redis缓存
RedisCacheManager.Builder builder = RedisCacheManager.builder
.redisConnectionFactory(redisConnectionFactory(environment))
.cacheDefaults(cacheConfiguration(environment));
return builder.build();
}
}
private RedisCacheConfiguration cacheConfiguration(Environment environment) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 根据环境配置缓存时间
long ttl = environment.getProperty("app.cache.ttl", Long.class, 3600L);
config = config.entryTtl(Duration.ofSeconds(ttl));
// 生产环境使用不同的序列化方式
if (environment.acceptsProfiles(Profiles.of("prod"))) {
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()));
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
return config;
}
private RedisConnectionFactory redisConnectionFactory(Environment environment) {
LettuceConnectionFactory factory = new LettuceConnectionFactory(
environment.getProperty("spring.redis.host", String.class, "localhost"),
environment.getProperty("spring.redis.port", Integer.class, 6379)
);
if (environment.acceptsProfiles(Profiles.of("prod"))) {
String password = environment.getProperty("spring.redis.password");
if (password != null && !password.isEmpty()) {
factory.setPassword(password);
}
factory.setDatabase(environment.getProperty("spring.redis.database", Integer.class, 0));
}
return factory;
}
}
配置优先级和覆盖策略
@Configuration
public class ConfigurationPriorityConfig {
@PostConstruct
public void demonstrateConfigurationPriority() {
ConfigurableEnvironment environment = getEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
// 配置优先级(从高到低)
// 1. 命令行参数
propertySources.addFirst(new SimpleCommandLinePropertySource(
"--app.name=CommandLineApp", "--server.port=9000"));
// 2. 系统属性
System.setProperty("app.name", "SystemPropertyApp");
// SystemEnvironmentPropertySource 已经存在且优先级较高
// 3. 环境变量
// SystemEnvironmentPropertySource 已经存在
// 4. 外部配置文件
try {
Resource externalResource = new FileSystemResource("/opt/app/config.properties");
if (externalResource.exists()) {
Properties externalProps = PropertiesLoaderUtils.loadProperties(externalResource);
propertySources.addAfter("systemProperties",
new PropertiesPropertySource("externalConfig", externalProps));
}
} catch (IOException e) {
// 外部配置文件不存在,忽略
}
// 5. classpath下的配置文件
propertySources.addBefore("applicationConfig: [classpath:/application.properties]",
new ResourcePropertySource("classpath:/default-config.properties"));
// 6. @PropertySource注解加载的配置
// @PropertySource的优先级取决于声明顺序
// 7. 默认配置
Map<String, Object> defaultConfig = new HashMap<>();
defaultConfig.put("app.name", "Default Application");
defaultConfig.put("app.version", "1.0.0");
defaultConfig.put("server.port", 8080);
propertySources.addLast(new MapPropertySource("defaultConfig", defaultConfig));
}
@Bean
public ConfigurationPropertySource demonstrateConfigurationPropertySource(Environment environment) {
// 使用Binder进行类型安全的属性绑定
Binder binder = Binder.get(environment);
// 1. 简单属性绑定
String appName = binder.bind("app.name", Bindable.of(String.class)).orElse("Default App");
Integer serverPort = binder.bind("server.port", Bindable.of(Integer.class)).orElse(8080);
// 2. 嵌套属性绑定
CacheConfig cacheConfig = binder.bind("app.cache", Bindable.of(CacheConfig.class)).orElse(new CacheConfig());
// 3. 集合属性绑定
List<String> modules = binder.bind("app.modules", Bindable.listOf(String.class)).orElse(Collections.emptyList());
Map<String, String> settings = binder.bind("app.settings", Bindable.mapOf(String.class, String.class))
.orElse(Collections.emptyMap());
// 4. 复杂对象绑定
DatabaseConfig databaseConfig = binder.bind("app.database", DatabaseConfig.class).orElse(null);
return new ConfigurationPropertySource() {
@Override
public ConfigurationPropertyName getConfigurationPropertyName() {
return ConfigurationPropertyName.of("demonstration");
}
@Override
public Object getUnderlyingSource() {
return this;
}
};
}
}
// 配置类
@Data
@Component
@ConfigurationProperties(prefix = "app.cache")
public static class CacheConfig {
private String type = "memory";
private int ttl = 3600;
private int maxSize = 1000;
}
@Data
public static class DatabaseConfig {
private String url;
private String username;
private String password;
private int maxConnections = 10;
private int connectionTimeout = 30000;
}
运行时配置变更
动态配置管理
@Component
public class DynamicConfigurationManager {
@Autowired
private ConfigurableEnvironment environment;
@Autowired
private ApplicationContext applicationContext;
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
@PostConstruct
public void init() {
// 定期检查配置变更
executor.scheduleAtFixedRate(this::checkForConfigurationChanges, 30, 30, TimeUnit.SECONDS);
}
public void checkForConfigurationChanges() {
try {
// 1. 检查外部配置文件变更
checkExternalConfigChanges();
// 2. 检查环境变量变更
checkEnvironmentVariableChanges();
// 3. 检查数据库配置变更
checkDatabaseConfigChanges();
// 4. 检查配置中心变更
checkConfigCenterChanges();
} catch (Exception e) {
System.err.println("检查配置变更时发生错误: " + e.getMessage());
}
}
private void checkExternalConfigChanges() {
String configPath = environment.getProperty("external.config.path");
if (configPath != null) {
Resource configFile = new FileSystemResource(configPath);
if (configFile.exists()) {
try {
Properties newProps = PropertiesLoaderUtils.loadProperties(configFile);
updatePropertySource("externalConfig", newProps);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void updatePropertySource(String propertySourceName, Properties newProperties) {
MutablePropertySources propertySources = environment.getPropertySources();
PropertySource<?> existingPropertySource = propertySources.get(propertySourceName);
if (existingPropertySource != null) {
// 检查属性是否有变更
Map<String, Object> existingProperties = new HashMap<>();
if (existingPropertySource.getSource() instanceof Map) {
existingProperties = (Map<String, Object>) existingPropertySource.getSource();
}
boolean hasChanges = false;
for (String key : newProperties.stringPropertyNames()) {
String newValue = newProperties.getProperty(key);
Object oldValue = existingProperties.get(key);
if (oldValue == null || !oldValue.equals(newValue)) {
hasChanges = true;
System.out.println("配置变更: " + key + " = " + newValue + " (原值: " + oldValue + ")");
}
}
if (hasChanges) {
// 更新属性源
PropertySource<?> newPropertySource = new PropertiesPropertySource(propertySourceName, newProperties);
propertySources.replace(propertySourceName, newPropertySource);
// 发布配置变更事件
applicationContext.publishEvent(new ConfigurationChangeEvent(propertySourceName, newProperties));
}
}
}
public void addOrUpdateProperty(String key, String value) {
MutablePropertySources propertySources = environment.getPropertySources();
// 查找可变的属性源
PropertySource<?> mutablePropertySource = propertySources.stream()
.filter(ps -> ps.getSource() instanceof MutablePropertySources ||
ps.getSource() instanceof Map)
.findFirst()
.orElse(null);
if (mutablePropertySource != null && mutablePropertySource.getSource() instanceof Map) {
Map<String, Object> sourceMap = (Map<String, Object>) mutablePropertySource.getSource();
Object oldValue = sourceMap.put(key, value);
System.out.println("属性更新: " + key + " = " + value + " (原值: " + oldValue + ")");
// 发布属性变更事件
Map<String, Object> changedProperties = new HashMap<>();
changedProperties.put(key, value);
applicationContext.publishEvent(new PropertyChangeEvent(changedProperties));
}
}
public String getProperty(String key) {
return environment.getProperty(key);
}
public <T> T getProperty(String key, Class<T> targetType) {
return environment.getProperty(key, targetType);
}
public String getRequiredProperty(String key) {
return environment.getRequiredProperty(key);
}
@PreDestroy
public void destroy() {
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
// 配置变更事件
public class ConfigurationChangeEvent extends ApplicationEvent {
private final String propertySourceName;
private final Properties properties;
public ConfigurationChangeEvent(String propertySourceName, Properties properties) {
super(propertySourceName);
this.propertySourceName = propertySourceName;
this.properties = properties;
}
public String getPropertySourceName() {
return propertySourceName;
}
public Properties getProperties() {
return properties;
}
}
public class PropertyChangeEvent extends ApplicationEvent {
private final Map<String, Object> changedProperties;
public PropertyChangeEvent(Map<String, Object> changedProperties) {
super(changedProperties);
this.changedProperties = changedProperties;
}
public Map<String, Object> getChangedProperties() {
return changedProperties;
}
}
// 配置变更监听器
@Component
public class ConfigurationChangeListener {
@EventListener
public void handleConfigurationChange(ConfigurationChangeEvent event) {
System.out.println("配置源 " + event.getPropertySourceName() + " 发生变更");
// 重新初始化相关组件
if (event.getPropertySourceName().equals("databaseConfig")) {
// 重新初始化数据库连接池
reinitializeDataSource();
} else if (event.getPropertySourceName().equals("cacheConfig")) {
// 重新初始化缓存
reinitializeCache();
}
}
@EventListener
public void handlePropertyChange(PropertyChangeEvent event) {
System.out.println("属性变更: " + event.getChangedProperties());
// 处理特定属性变更
event.getChangedProperties().forEach((key, value) -> {
if (key.startsWith("app.feature.")) {
// 功能开关变更
String featureName = key.substring("app.feature.".length());
boolean enabled = Boolean.parseBoolean(value.toString());
updateFeatureStatus(featureName, enabled);
}
});
}
private void reinitializeDataSource() {
// 重新初始化数据源逻辑
System.out.println("重新初始化数据源...");
}
private void reinitializeCache() {
// 重新初始化缓存逻辑
System.out.println("重新初始化缓存...");
}
private void updateFeatureStatus(String featureName, boolean enabled) {
// 更新功能状态逻辑
System.out.println("功能 " + featureName + " 状态更新为: " + (enabled ? "启用" : "禁用"));
}
}
🎯 经典面试题
Q1:Spring Environment的作用是什么?
答案要点:
- 统一配置抽象:提供统一的配置访问接口
- Profile管理:管理多环境配置
- 属性源管理:管理多个配置源
- 类型安全:支持类型安全的属性访问
- 动态配置:支持运行时配置变更
Q2:Spring的属性源优先级是怎样的?
答案要点:
| 优先级 | 属性源类型 | 说明 |
|---|---|---|
| 1 | 命令行参数 | --server.port=8080 |
| 2 | Java系统属性 | System.setProperty() |
| 3 | 操作系统环境变量 | export SERVER_PORT=8080 |
| 4 | 外部配置文件 | application-{profile}.properties |
| 5 | @PropertySource | @PropertySource("classpath:config.properties") |
| 6 | 默认配置 | 默认属性值 |
Q3:如何实现动态配置刷新?
答案要点:
- 监听配置变更:通过Environment监听配置变化
- 更新属性源:动态修改PropertySource
- 发布事件:通过ApplicationEvent发布变更事件
- 监听事件:监听配置变更事件并更新组件
- 重新初始化:重新初始化受影响的Bean
Q4:Environment和PropertySource有什么关系?
答案要点:
- Environment:环境抽象接口,统一配置访问
- PropertySource:属性源接口,提供配置数据
- 关系:Environment管理多个PropertySource
- 优先级:PropertySource有明确的优先级顺序
- 查询顺序:Environment按优先级顺序查询PropertySource
经典面试题集锦
综合面试题
Spring性能调优
容器启动性能优化
Bean定义优化
@Configuration
public class ContainerPerformanceConfig {
// 1. 延迟加载Bean
@Lazy
@Bean
public ExpensiveService expensiveService() {
// 只有在第一次使用时才会创建
return new ExpensiveService();
}
// 2. 条件化Bean创建
@Bean
@ConditionalOnProperty(name = "feature.cache.enabled", havingValue = "true")
public CacheManager cacheManager() {
return new RedisCacheManager();
}
@Bean
@ConditionalOnMissingBean(CacheManager.class)
public CacheManager simpleCacheManager() {
return new ConcurrentMapCacheManager();
}
// 3. 作用域优化
@Bean
@Scope("prototype") // 原型作用域,每次注入新实例
public HeavyResource heavyResource() {
return new HeavyResource();
}
// 4. 工厂方法优化
@Bean
public DataSource dataSource() {
// 使用Builder模式创建复杂对象
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.url(getDatabaseUrl())
.username(getDatabaseUsername())
.password(getDatabasePassword())
.build();
}
private String getDatabaseUrl() {
// 缓存计算结果
return this.cachedDatabaseUrl;
}
private String getDatabaseUsername() {
return this.cachedDatabaseUsername;
}
private String getDatabasePassword() {
return this.cachedDatabasePassword;
}
// 5. BeanPostProcessor优化
@Bean
public static BeanPostProcessor performanceBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 避免在PostProcessor中进行耗时操作
if (bean instanceof PerformanceAware) {
((PerformanceAware) bean).enablePerformanceMonitoring();
}
return bean;
}
};
}
}
// 性能感知接口
public interface PerformanceAware {
void enablePerformanceMonitoring();
}
// 6. 依赖注入优化
@Component
public class OptimizedService {
// 避免循环依赖
private final Lazy<UserService> lazyUserService;
private final Provider<OrderService> orderServiceProvider; // JSR-330 Provider
// 使用构造器注入
public OptimizedService(Lazy<UserService> lazyUserService,
Provider<OrderService> orderServiceProvider) {
this.lazyUserService = lazyUserService;
this.orderServiceProvider = orderServiceProvider;
}
public void performOperation() {
// 延迟获取Bean实例
UserService userService = lazyUserService.get();
OrderService orderService = orderServiceProvider.get();
// 业务逻辑
}
}
ApplicationContext优化
@Configuration
public class ApplicationContextPerformanceConfig {
// 1. 启用注解配置处理器
@Bean
public static ConfigurationClassPostProcessor configurationClassPostProcessor() {
ConfigurationClassPostProcessor processor = new ConfigurationClassPostProcessor();
processor.setAutowiredAnnotationTypes(Set.of(
Autowired.class,
Qualifier.class,
Value.class,
Resource.class,
Inject.class
));
return processor;
}
// 2. 优化组件扫描
@ComponentScan(basePackages = "com.example",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = {TestController.class, MockService.class}),
@ComponentScan.Filter(type = FilterType.REGEX,
pattern = "com.example.test..*")
})
public class ComponentScanConfig {
// 只扫描需要的组件
}
// 3. 自定义BeanFactoryPostProcessor
@Bean
public static BeanFactoryPostProcessor customBeanFactoryPostProcessor() {
return beanFactory -> {
// 优化BeanFactory配置
if (beanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
// 设置缓存元数据
dlbf.setCacheBeanMetadata(false); // 避免缓存Bean元数据
// 设置允许循环引用
dlbf.setAllowCircularReferences(false); // 禁止循环引用
// 设置允许Bean定义覆盖
dlbf.setAllowBeanDefinitionOverriding(false);
}
};
}
// 4. 条件化配置加载
@Configuration
@ConditionalOnProperty(name = "app.performance.optimization", havingValue = "true")
static class PerformanceOptimizationConfig {
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
@Bean
public PerformanceFilter performanceFilter() {
return new PerformanceFilter();
}
}
}
AOP性能优化
代理优化策略
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false, exposeProxy = false)
public class AopPerformanceConfig {
// 1. 优化代理创建
@Bean
public static AnnotationAwareAspectJAutoProxyCreator aspectJAutoProxyCreator() {
AnnotationAwareAspectJAutoProxyCreator creator = new AnnotationAwareAspectJAutoProxyCreator();
// 禁用CGLIB优化,使用JDK动态代理(更快)
creator.setProxyTargetClass(false);
// 不暴露代理对象
creator.setExposeProxy(false);
// 设置是否预检测目标对象
creator.setPreferInfrastructuralBeans(true);
return creator;
}
// 2. 优化切面匹配
@Aspect
@Component
public class OptimizedLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(OptimizedLoggingAspect.class);
// 使用具体包路径,避免全局扫描
@Pointcut("execution(* com.example.service..*(..))")
public void serviceLayer() {}
// 优化切点表达式,减少匹配时间
@Pointcut("execution(* com.example.service.*Service.*(..))")
public void specificServiceMethods() {}
// 使用@Around替代@Before + @After的组合
@Around("serviceLayer()")
public Object logServiceMethods(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.nanoTime();
try {
Object result = joinPoint.proceed();
// 只在DEBUG级别记录详细信息
if (logger.isDebugEnabled()) {
long duration = System.nanoTime() - startTime;
logger.debug("执行方法: {}, 耗时: {} ns",
joinPoint.getSignature().toShortString(), duration);
}
return result;
} catch (Exception e) {
logger.error("方法执行异常: {}", joinPoint.getSignature().toShortString(), e);
throw e;
}
}
// 批量处理通知
@AfterReturning(pointcut = "execution(* com.example.batch.*.processBatch(..))",
returning = "result")
public void logBatchProcessing(JoinPoint joinPoint, Object result) {
// 批量操作的特殊处理
logger.info("批量处理完成: {}", joinPoint.getSignature().toShortString());
}
}
// 3. 性能监控切面
@Aspect
@Component
@ConditionalOnProperty(name = "performance.monitoring.enabled", havingValue = "true")
public class PerformanceMonitoringAspect {
private final MeterRegistry meterRegistry;
private final Map<String, Timer> timers = new ConcurrentHashMap<>();
public PerformanceMonitoringAspect(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Around("@annotation(Monitored)")
public Object monitorMethod(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().toShortString();
Timer timer = timers.computeIfAbsent(methodName,
name -> Timer.builder("method.execution.time")
.tag("method", methodName)
.register(meterRegistry));
return timer.recordCallable(() -> {
try {
return joinPoint.proceed();
} catch (Throwable e) {
meterRegistry.counter("method.execution.error", "method", methodName).increment();
throw e;
}
});
}
}
}
// 监控注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitored {
String value() default "";
}
数据访问性能优化
连接池优化
@Configuration
public class DatabasePerformanceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource() {
HikariConfig config = new HikariConfig();
// 基础配置
config.setMinimumIdle(5);
config.setMaximumPoolSize(20);
config.setIdleTimeout(300000); // 5分钟
config.setConnectionTimeout(20000); // 20秒
config.setMaxLifetime(1800000); // 30分钟
// 性能优化配置
config.setLeakDetectionThreshold(60000); // 连接泄漏检测
config.setValidationTimeout(5000); // 连接验证超时
config.setConnectionTestQuery("SELECT 1");
// JPA优化配置
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
config.addDataSourceProperty("useServerPrepStmts", "true");
config.addDataSourceProperty("useLocalSessionState", "true");
config.addDataSourceProperty("rewriteBatchedStatements", "true");
config.addDataSourceProperty("cacheResultSetMetadata", "true");
config.addDataSourceProperty("cacheServerConfiguration", "true");
config.addDataSourceProperty("elideSetAutoCommits", "true");
config.addDataSourceProperty("maintainTimeStats", "false");
return new HikariDataSource(config);
}
// JPA性能优化
@Bean
@ConfigurationProperties(prefix = "spring.jpa")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setPackagesToScan("com.example.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
// JPA性能属性
Properties jpaProperties = new Properties();
// 二级缓存配置
jpaProperties.put("hibernate.cache.use_second_level_cache", "true");
jpaProperties.put("hibernate.cache.use_query_cache", "true");
jpaProperties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.jcache.JCacheRegionFactory");
// 查询优化
jpaProperties.put("hibernate.jdbc.fetch_size", "100");
jpaProperties.put("hibernate.jdbc.batch_size", "20");
jpaProperties.put("hibernate.order_inserts", "true");
jpaProperties.put("hibernate.order_updates", "true");
// 连接和事务优化
jpaProperties.put("hibernate.connection.provider_disables_autocommit", "true");
jpaProperties.put("hibernate.jdbc.batch_versioned_data", "true");
// 统计和监控(生产环境应设为false)
jpaProperties.put("hibernate.generate_statistics", "false");
emf.setJpaProperties(jpaProperties);
return emf;
}
// 二级缓存配置
@Bean
public JCacheCacheManager cacheManager(javax.cache.CacheManager cacheManager) {
return new JCacheCacheManager(cacheManager);
}
@Bean
public javax.cache.CacheManager jCacheCacheManager() {
CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManagerBuilder<javax.cache.CacheManager> cacheManagerBuilder =
cachingProvider.getCacheManagerBuilder();
return cacheManagerBuilder.build();
}
}
查询优化
@Repository
public class OptimizedRepository {
@PersistenceContext
private EntityManager entityManager;
// 1. 批量操作优化
@Transactional
public void batchInsert(List<Entity> entities) {
final int batchSize = 20;
for (int i = 0; i < entities.size(); i++) {
entityManager.persist(entities.get(i));
if (i % batchSize == 0) {
// 定期刷新和清理,避免内存溢出
entityManager.flush();
entityManager.clear();
}
}
// 最后一次刷新
entityManager.flush();
entityManager.clear();
}
// 2. 查询优化
public List<Entity> findOptimized(String criteria) {
return entityManager.createQuery(
"SELECT e FROM Entity e WHERE e.criteria = :criteria", Entity.class)
.setParameter("criteria", criteria)
.setHint("javax.persistence.fetchgraph", entityManager.getEntityGraph("entity.full"))
.setHint("org.hibernate.fetchSize", 100)
.setHint("org.hibernate.cacheable", true)
.getResultList();
}
// 3. 分页查询优化
public Page<Entity> findPageOptimized(Pageable pageable) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> root = query.from(Entity.class);
// 使用COUNT查询优化总数统计
CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
countQuery.select(cb.count(countQuery.from(Entity.class)));
Long total = entityManager.createQuery(countQuery)
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
// 设置分页参数
TypedQuery<Entity> typedQuery = entityManager.createQuery(query);
typedQuery.setFirstResult((int) pageable.getOffset());
typedQuery.setMaxResults(pageable.getPageSize());
List<Entity> content = typedQuery.getResultList();
return new PageImpl<>(content, pageable, total);
}
// 4. 原生SQL优化
@Query(value = "SELECT * FROM large_table WHERE status = ?1 LIMIT ?2",
nativeQuery = true)
List<LargeEntity> findLimitedByStatus(String status, int limit);
// 5. 存储过程调用优化
@Procedure(name = "optimized_procedure")
@Transactional
void callOptimizedProcedure(@Param("param1") String param1, @Param("param2") Integer param2);
}
缓存性能优化
多级缓存配置
@Configuration
@EnableCaching
public class CachePerformanceConfig {
@Bean
@Primary
public CacheManager cacheManager() {
// 创建多级缓存管理器
CompositeCacheManager compositeCacheManager = new CompositeCacheManager();
// L1: 本地缓存(最快)
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.recordStats());
// L2: 分布式缓存
RedisCacheManager redisCacheManager = RedisCacheManager.builder
(redisConnectionFactory())
.cacheDefaults(cacheConfiguration())
.transactionAware()
.build();
compositeCacheManager.setCacheManagers(
Arrays.asList(caffeineCacheManager, redisCacheManager));
return compositeCacheManager;
}
private RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
}
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofSeconds(2))
.shutdownTimeout(Duration.ZERO)
.build();
return new LettuceConnectionFactory(
new RedisStandaloneConfiguration("localhost", 6379), clientConfig);
}
// 缓存预热
@EventListener
public void handleApplicationReady(ApplicationReadyEvent event) {
// 应用启动后预加载热点数据
preloadCache();
}
private void preloadCache() {
ExecutorService executor = Executors.newFixedThreadPool(5);
try {
// 并行预加载多个缓存
executor.submit(() -> loadUserCache());
executor.submit(() -> loadProductCache());
executor.submit(() -> loadConfigCache());
executor.submit(() -> loadPermissionCache());
executor.submit(() -> loadDictionaryCache());
executor.shutdown();
executor.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 缓存注解优化
@Service
public class CacheOptimizedService {
// 读操作:优先从缓存读取
@Cacheable(value = "users", key = "#id",
condition = "#id != null", unless = "#result == null")
public User getUser(Long id) {
// 数据库查询
return userRepository.findById(id).orElse(null);
}
// 写操作:同步更新缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
// 删除操作:清除缓存
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
// 批量操作:缓存操作
@Caching(
evict = {
@CacheEvict(value = "users", allEntries = true),
@CacheEvict(value = "user-stats", allEntries = true)
}
)
@Transactional
public void batchUpdateUsers(List<User> users) {
userRepository.saveAll(users);
}
// 复杂查询:结果缓存
@Cacheable(value = "user-search", key = "#criteria.hashCode()")
public Page<User> searchUsers(UserSearchCriteria criteria, Pageable pageable) {
return userRepository.search(criteria, pageable);
}
}
}
异步处理优化
异步配置优化
@Configuration
@EnableAsync
public class AsyncPerformanceConfig implements AsyncConfigurer {
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
// 最大线程数
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
// 队列容量
executor.setQueueCapacity(1000);
// 线程名称前缀
executor.setThreadNamePrefix("async-");
// 拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待任务完成后关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
// 预启动核心线程
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// 异步异常处理
log.error("异步方法执行异常", ex);
// 发送告警
alertService.sendAlert("异步执行异常", method.getName());
}
};
}
// 专门的IO密集型任务线程池
@Bean(name = "ioIntensiveExecutor")
public Executor ioIntensiveExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(2000);
executor.setThreadNamePrefix("io-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
// CPU密集型任务线程池
@Bean(name = "cpuIntensiveExecutor")
public Executor cpuIntensiveExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int processors = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(processors);
executor.setMaxPoolSize(processors);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("cpu-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
// 异步服务优化
@Service
public class AsyncOptimizedService {
@Async("taskExecutor")
public CompletableFuture<String> processAsyncTask(String input) {
try {
// 异步业务处理
String result = heavyProcessing(input);
return CompletableFuture.completedFuture(result);
} catch (Exception e) {
return CompletableFuture.failedFuture(e);
}
}
@Async("ioIntensiveExecutor")
public CompletableFuture<List<String>> batchIoOperations(List<String> inputs) {
return CompletableFuture.supplyAsync(() -> {
return inputs.parallelStream()
.map(this::ioOperation)
.collect(Collectors.toList());
});
}
@Async("cpuIntensiveExecutor")
public CompletableFuture<CalculationResult> complexCalculation(CalculationData data) {
return CompletableFuture.supplyAsync(() -> {
return performComplexCalculation(data);
});
}
// 异步批量处理
@Async("taskExecutor")
public CompletableFuture<BatchResult> batchProcess(List<BatchItem> items) {
int batchSize = 50;
List<CompletableFuture<List<BatchItem>>> futures = new ArrayList<>();
for (int i = 0; i < items.size(); i += batchSize) {
int end = Math.min(i + batchSize, items.size());
List<BatchItem> batch = items.subList(i, end);
CompletableFuture<List<BatchItem>> future = CompletableFuture.supplyAsync(() -> {
return batch.stream()
.map(this::processBatchItem)
.filter(Objects::nonNull)
.collect(Collectors.toList());
});
futures.add(future);
}
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> {
List<BatchItem> allResults = futures.stream()
.map(CompletableFuture::join)
.flatMap(List::stream)
.collect(Collectors.toList());
return new BatchResult(allResults, allResults.size(), items.size());
});
}
}
内存和GC优化
内存优化配置
@Configuration
public class MemoryOptimizationConfig {
// 1. 对象池配置
@Bean
public ObjectPool<ExpensiveObject> expensiveObjectPool() {
return new GenericObjectPool<>(new ExpensiveObjectFactory());
}
// 2. 字符串池优化
@Bean
public ConcurrentMap<String, String> stringCache() {
return CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterAccess(30, TimeUnit.MINUTES)
.build()
.asMap();
}
// 3. 内存监控
@Bean
public MemoryMonitor memoryMonitor() {
return new MemoryMonitor();
}
}
// 内存监控组件
@Component
public class MemoryMonitor {
private static final Logger logger = LoggerFactory.getLogger(MemoryMonitor.class);
@Scheduled(fixedRate = 30000) // 每30秒检查一次
public void monitorMemory() {
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage();
long heapUsed = heapUsage.getUsed();
long heapMax = heapUsage.getMax();
double heapUsagePercent = (double) heapUsed / heapMax * 100;
long nonHeapUsed = nonHeapUsage.getUsed();
long nonHeapMax = nonHeapUsage.getMax();
double nonHeapUsagePercent = (double) nonHeapUsed / nonHeapMax * 100;
logger.info("堆内存使用: {} / {} ({}%)",
formatBytes(heapUsed), formatBytes(heapMax), String.format("%.2f", heapUsagePercent));
logger.info("非堆内存使用: {} / {} ({}%)",
formatBytes(nonHeapUsed), formatBytes(nonHeapMax), String.format("%.2f", nonHeapUsagePercent));
// 内存使用率超过80%时告警
if (heapUsagePercent > 80.0) {
logger.warn("堆内存使用率过高: {}%", String.format("%.2f", heapUsagePercent));
alertService.sendAlert("内存告警", "堆内存使用率过高");
}
// 触发GC
if (heapUsagePercent > 85.0) {
logger.warn("触发垃圾回收");
System.gc();
}
}
private String formatBytes(long bytes) {
String[] units = {"B", "KB", "MB", "GB", "TB"};
int digitGroups = (int) (Math.log10(bytes) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(bytes / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
}
// 对象池工厂
public class ExpensiveObjectFactory extends BasePooledObjectFactory<ExpensiveObject> {
@Override
public ExpensiveObject create() {
return new ExpensiveObject(); // 创建耗时对象
}
@Override
public PooledObject<ExpensiveObject> wrap(ExpensiveObject obj) {
return new DefaultPooledObject<>(obj);
}
@Override
public boolean validateObject(PooledObject<ExpensiveObject> p) {
return p.getObject().isValid(); // 验证对象有效性
}
@Override
public void passivateObject(PooledObject<ExpensiveObject> p) {
p.getObject().reset(); // 重置对象状态
}
}
🎯 经典面试题
Q1:Spring应用如何进行性能优化?
答案要点:
- 容器优化:延迟加载、作用域优化、Bean定义优化
- AOP优化:代理类型选择、切点表达式优化、批量通知
- 数据访问优化:连接池配置、批量操作、查询优化
- 缓存优化:多级缓存、缓存预热、缓存策略
- 异步优化:线程池配置、任务拆分、异常处理
Q2:Spring如何优化Bean的创建和初始化?
答案要点:
- 延迟加载:@Lazy注解延迟Bean创建
- 作用域选择:合理选择singleton/prototype
- 依赖注入优化:构造器注入避免循环依赖
- FactoryBean:使用工厂Bean创建复杂对象
- BeanPostProcessor:避免在PostProcessor中做耗时操作
Q3:Spring AOP性能优化的最佳实践?
答案要点:
- 代理选择:优先使用JDK动态代理,避免CGLIB
- 切点优化:使用具体的包路径,避免全局扫描
- 通知合并:使用@Around替代@Before + @After组合
- 缓存优化:缓存切点匹配结果
- 条件执行:根据日志级别决定是否执行切面逻辑
Q4:Spring数据访问层如何优化性能?
答案要点:
- 连接池优化:HikariCP配置参数调优
- 批量操作:使用批量插入/更新减少数据库交互
- 查询优化:合理使用分页、索引、查询缓存
- 事务优化:选择合适的传播行为和隔离级别
- 二级缓存:配置Hibernate二级缓存提升查询性能
综合面试题
Q1:Spring框架的核心是什么,如何理解IoC和AOP?
答案要点:
IoC(控制反转):
- 概念:将对象的创建和依赖关系的管理交给Spring容器
- 好处:降低耦合、便于测试、提高复用性
- 实现:通过BeanFactory和ApplicationContext实现
- 依赖注入:构造器注入、Setter注入、字段注入
AOP(面向切面编程):
- 概念:将横切关注点(日志、事务、安全等)模块化
- 核心术语:切面、连接点、通知、切点
- 实现:基于动态代理(JDK Proxy或CGLIB)
- 应用场景:日志记录、事务管理、权限控制
Q2:Spring如何解决Bean循环依赖?
答案要点:
三级缓存机制:
- 一级缓存(singletonObjects):存放完全初始化的单例Bean
- 二级缓存(earlySingletonObjects):存放提前暴露的半成品Bean
- 三级缓存(singletonFactories):存放Bean工厂,用于生成代理对象
解决过程:
- A创建实例,放入三级缓存
- A需要注入B,开始创建B
- B创建实例,放入三级缓存
- B需要注入A,从三级缓存获取A的代理对象
- B初始化完成,放入一级缓存
- A获得B的引用,初始化完成,放入一级缓存
无法解决的情况:
- 构造器注入的循环依赖
- 原型Bean的循环依赖
Q3:Spring事务是如何实现的?什么时候会失效?
答案要点:
实现原理:
- AOP机制:通过AOP在方法前后添加事务管理逻辑
- 事务管理器:PlatformTransactionManager统一管理事务
- 事务同步:TransactionSynchronizationManager管理事务状态
- 异常处理:根据配置决定是否回滚
失效场景:
- 方法不是public:AOP只能代理public方法
- 自调用问题:类内部方法调用不经过代理
- 异常类型不匹配:检查异常默认不回滚
- 传播行为错误:如NOT_SUPPORTED、NEVER等
- 数据库引擎不支持:如MyISAM不支持事务
- 多线程调用:不同线程不在同一事务中
Q4:Spring MVC和Spring Boot有什么区别?
答案要点:
Spring MVC:
- 定位:Web框架,用于构建Web应用
- 功能:MVC模式、请求处理、视图渲染
- 配置:需要手动配置DispatcherServlet、视图解析器等
- 依赖:需要手动添加依赖
Spring Boot:
- 定位:应用开发框架,简化Spring应用开发
- 功能:自动配置、起步依赖、内嵌服务器
- 配置:大量自动配置,减少手动配置
- 依赖:通过starter简化依赖管理
**关系:**Spring Boot包含并简化了Spring MVC的使用
Q5:如何在Spring中实现异步处理?
答案要点:
@EnableAsync配置:
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}
使用@Async:
@Service
public class EmailService {
@Async
public CompletableFuture<String> sendEmail(String to, String subject) {
// 异步发送邮件
try {
Thread.sleep(1000); // 模拟耗时操作
return CompletableFuture.completedFuture("邮件发送成功");
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
}
}
}
高级面试题
Q6:Spring Cloud和Spring Boot的关系是什么?
答案要点:
Spring Boot:
- 作用:简化Spring应用开发
- 范围:单个应用的开发和部署
- 功能:自动配置、起步依赖、内嵌服务器
Spring Cloud:
- 作用:构建微服务架构
- 范围:多个服务的协调和管理
- 功能:服务发现、配置中心、熔断器、网关
关系:
- Spring Cloud基于Spring Boot构建
- Spring Cloud提供了分布式系统的解决方案
- Spring Boot简化了微服务的开发
Q7:Spring如何实现REST API的最佳实践?
答案要点:
RESTful API设计:
- HTTP方法使用:GET(查询)、POST(创建)、PUT(更新)、DELETE(删除)
- 资源命名:使用名词而非动词
- 状态码使用:正确使用HTTP状态码
- 统一响应格式:定义统一的响应结构
最佳实践:
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
// 统一响应格式
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<User>> getUser(@PathVariable Long id) {
User user = userService.findById(id);
return ResponseEntity.ok(ApiResponse.success(user));
}
// 参数验证
@PostMapping
public ResponseEntity<ApiResponse<User>> createUser(@Valid @RequestBody CreateUserRequest request) {
User user = userService.create(request);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success(user));
}
// 异常处理
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException e) {
return ResponseEntity.badRequest()
.body(ApiResponse.error(e.getMessage()));
}
}
Q8:Spring Security的工作原理是什么?
答案要点:
核心组件:
- Authentication:认证信息接口
- SecurityContextHolder:安全上下文持有者
- AuthenticationManager:认证管理器
- UserDetailsService:用户详情服务
- FilterChain:过滤器链
认证流程:
- 用户请求:通过FilterChain
- 身份认证:AuthenticationManager进行认证
- 权限检查:授权管理器检查权限
- 访问控制:决定是否允许访问
💡 学习建议
1. 学习路径建议
初学者路径:
- Java基础 → 2. Spring Core(IoC/DI) → 3. Spring AOP → 4. Spring MVC → 5. Spring Boot
进阶路径:
- Spring Boot进阶 → 2. Spring Cloud → 3. Spring Security → 4. Spring Data JPA → 5. Spring Transaction
2. 实践项目建议
项目一:简单CRUD系统
- 使用Spring Boot + Spring MVC
- 实现用户管理功能
- 练习基本的增删改查操作
项目二:REST API服务
- 设计RESTful API
- 实现数据验证和异常处理
- 添加日志和监控
项目三:微服务架构
- 使用Spring Cloud
- 实现服务注册发现
- 添加配置中心和服务网关
3. 面试准备重点
必须掌握:
- IoC和AOP原理
- Spring Bean生命周期
- Spring事务管理
- Spring MVC流程
- Spring Boot自动配置
加分项:
- Spring Cloud微服务
- Spring Security安全框架
- Spring Data JPA数据访问
- 性能优化经验
📝 总结
Spring框架是Java开发中最重要的框架之一,掌握Spring的核心原理对于Java开发者来说至关重要。通过本文档的学习,你应该能够:
- 理解Spring核心概念:IoC、AOP、Bean管理
- 掌握Spring开发技能:事务管理、Web开发、配置管理
- 具备面试准备能力:经典面试题、实战经验
- 形成完整知识体系:从基础到进阶的学习路径
记住,理论学习要结合实际项目,只有通过实践才能真正掌握Spring框架的精髓。祝你学习顺利,面试成功!