引言
Spring是Java开发中最流行的框架,几乎是面试必考内容。本文系统梳理Spring核心知识点和高频面试题,帮助你全面掌握Spring框架。
一、Spring核心概念
1.1 什么是Spring?
Spring是一个轻量级的Java开发框架,主要特性:
- IOC(控制反转):对象的创建和依赖关系由Spring容器管理
- AOP(面向切面编程):通过代理实现横切关注点
- 声明式事务:通过注解管理事务
- MVC框架:Spring MVC提供Web开发支持
- 集成支持:轻松集成MyBatis、Hibernate等框架
1.2 Spring的优势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class UserService { private UserDao userDao = new UserDaoImpl(); }
@Service public class UserService { @Autowired private UserDao userDao; }
@Test public void testUserService() { UserDao mockDao = mock(UserDao.class); UserService service = new UserService(mockDao); }
@Transactional public void transferMoney(Long from, Long to, BigDecimal amount) { }
|
二、IOC容器
2.1 什么是IOC?
IOC(Inversion of Control)控制反转:将对象的创建权交给Spring容器。
1 2 3 4 5 6 7 8 9 10
| UserService service = new UserService(); service.setUserDao(new UserDaoImpl());
@Service public class UserService { @Autowired private UserDao userDao; }
|
DI(Dependency Injection)依赖注入是IOC的实现方式。
2.2 依赖注入的三种方式
1. 构造器注入(推荐)
1 2 3 4 5 6 7 8 9
| @Service public class UserService { private final UserDao userDao; public UserService(UserDao userDao) { this.userDao = userDao; } }
|
优点:
- 依赖不可变(final)
- 避免NullPointerException
- 便于测试
2. Setter注入
1 2 3 4 5 6 7 8 9
| @Service public class UserService { private UserDao userDao; @Autowired public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
|
3. 字段注入(不推荐)
1 2 3 4 5
| @Service public class UserService { @Autowired private UserDao userDao; }
|
2.3 Bean的作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Scope("singleton") @Component public class SingletonBean { }
@Scope("prototype") @Component public class PrototypeBean { }
@Scope("request") @Component public class RequestBean { }
@Scope("session") @Component public class SessionBean { }
@Scope("application") @Component public class ApplicationBean {}
|
2.4 Bean的生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| @Component public class MyBean implements InitializingBean, DisposableBean { private String name; public MyBean() { System.out.println("1. 构造器"); } public void setName(String name) { System.out.println("2. 设置属性:" + name); this.name = name; } @Override public void setBeanName(String name) { System.out.println("3. setBeanName:" + name); } @Override public void setBeanFactory(BeanFactory beanFactory) { System.out.println("4. setBeanFactory"); } @Override public void setApplicationContext(ApplicationContext context) { System.out.println("5. setApplicationContext"); } @PostConstruct public void init() { System.out.println("7. @PostConstruct"); } @Override public void afterPropertiesSet() { System.out.println("8. afterPropertiesSet"); } public void customInit() { System.out.println("9. customInit"); } @PreDestroy public void preDestroy() { System.out.println("11. @PreDestroy"); } @Override public void destroy() { System.out.println("12. destroy"); } public void customDestroy() { System.out.println("13. customDestroy"); } }
|
简化版流程:
1 2 3 4
| 实例化 → 属性注入 → Aware接口 → BeanPostProcessor前置 → @PostConstruct → InitializingBean → init-method → BeanPostProcessor后置 → Bean使用 → @PreDestroy → DisposableBean → destroy-method
|
2.5 循环依赖问题
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class A { @Autowired private B b; }
@Component public class B { @Autowired private A a; }
|
Spring如何解决循环依赖?
通过三级缓存:
注意:构造器注入无法解决循环依赖!
三、AOP面向切面编程
3.1 什么是AOP?
AOP(Aspect Oriented Programming):将横切关注点从业务逻辑中分离出来。
横切关注点:日志、事务、权限等通用功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public void transfer(Long from, Long to, BigDecimal amount) { System.out.println("开始转账"); accountDao.deduct(from, amount); accountDao.add(to, amount); System.out.println("转账完成"); }
@Aspect @Component public class LogAspect { @Around("execution(* com.example.service.*.*(..))") public Object log(ProceedingJoinPoint pjp) throws Throwable { System.out.println("开始转账"); Object result = pjp.proceed(); System.out.println("转账完成"); return result; } }
public void transfer(Long from, Long to, BigDecimal amount) { accountDao.deduct(from, amount); accountDao.add(to, amount); }
|
3.2 AOP核心概念
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Aspect @Component public class LogAspect {}
@Pointcut("execution(* com.example.service.*.*(..))") public void serviceMethod() {}
@Before("serviceMethod()") @After("serviceMethod()") @AfterReturning("serviceMethod()") @AfterThrowing("serviceMethod()") @Around("serviceMethod()")
|
3.3 五种通知类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Aspect @Component public class MyAspect { @Before("execution(* com.example.service.*.*(..))") public void before(JoinPoint jp) { System.out.println("前置通知:" + jp.getSignature().getName()); } @After("execution(* com.example.service.*.*(..))") public void after(JoinPoint jp) { System.out.println("后置通知"); } @AfterReturning(value = "execution(* com.example.service.*.*(..))", returning = "result") public void afterReturning(JoinPoint jp, Object result) { System.out.println("返回通知:" + result); } @AfterThrowing(value = "execution(* com.example.service.*.*(..))", throwing = "ex") public void afterThrowing(JoinPoint jp, Exception ex) { System.out.println("异常通知:" + ex.getMessage()); } @Around("execution(* com.example.service.*.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("环绕前"); Object result = pjp.proceed(); System.out.println("环绕后"); return result; } }
|
执行顺序:
1 2 3 4 5
| 正常执行: Around前 → Before → 方法执行 → AfterReturning → After → Around后
异常执行: Around前 → Before → 方法执行(异常)→ AfterThrowing → After
|
3.4 切点表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@Pointcut("execution(public * com.example.service.*.*(..))")
@Pointcut("within(com.example.service.*)")
@Pointcut("this(com.example.service.UserService)")
@Pointcut("target(com.example.service.UserService)")
@Pointcut("args(Long, String)")
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
@Pointcut("@within(org.springframework.stereotype.Service)")
@Pointcut("@target(org.springframework.stereotype.Service)")
@Pointcut("@args(com.example.annotation.Valid)")
@Pointcut("execution(* com.example.service.*.*(..)) && @annotation(log)")
|
3.5 AOP实战:性能监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @Aspect @Component @Slf4j public class PerformanceAspect { @Around("@annotation(com.example.annotation.Monitor)") public Object monitor(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); String className = pjp.getTarget().getClass().getSimpleName(); String methodName = pjp.getSignature().getName(); Object[] args = pjp.getArgs(); log.info("开始执行:{}.{},参数:{}", className, methodName, args); Object result = null; try { result = pjp.proceed(); long end = System.currentTimeMillis(); log.info("执行完成:{}.{},耗时:{}ms", className, methodName, (end - start)); return result; } catch (Throwable e) { long end = System.currentTimeMillis(); log.error("执行异常:{}.{},耗时:{}ms,异常:{}", className, methodName, (end - start), e.getMessage()); throw e; } } }
@Service public class UserService { @Monitor public User getUser(Long id) { return user; } }
|
四、事务管理
4.1 Spring事务的实现方式
1. 编程式事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Autowired private TransactionTemplate transactionTemplate;
public void transfer(Long from, Long to, BigDecimal amount) { transactionTemplate.execute(status -> { try { accountDao.deduct(from, amount); accountDao.add(to, amount); return true; } catch (Exception e) { status.setRollbackOnly(); return false; } }); }
|
2. 声明式事务(推荐)
1 2 3 4 5
| @Transactional public void transfer(Long from, Long to, BigDecimal amount) { accountDao.deduct(from, amount); accountDao.add(to, amount); }
|
4.2 @Transactional属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Transactional( // 1. 传播行为 propagation = Propagation.REQUIRED, // 2. 隔离级别 isolation = Isolation.DEFAULT, // 3. 超时时间(秒) timeout = 30, // 4. 只读事务 readOnly = false, // 5. 回滚异常 rollbackFor = Exception.class, // 6. 不回滚异常 noRollbackFor = RuntimeException.class ) public void method() {}
|
4.3 事务传播行为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Transactional(propagation = Propagation.REQUIRED) public void methodA() { methodB(); }
@Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() { }
@Transactional(propagation = Propagation.SUPPORTS)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Transactional(propagation = Propagation.MANDATORY)
@Transactional(propagation = Propagation.NEVER)
@Transactional(propagation = Propagation.NESTED)
|
4.4 事务失效场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @Transactional private void method() {}
@Service public class UserService { public void methodA() { this.methodB(); } @Transactional public void methodB() {} }
@Autowired private UserService self;
public void methodA() { self.methodB(); }
@Transactional public void method() { try { } catch (Exception e) { } }
@Transactional public void method() throws Exception { throw new Exception(); }
@Transactional(rollbackFor = Exception.class)
|
五、Spring MVC
5.1 MVC架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 客户端请求 ↓ DispatcherServlet(前端控制器) ↓ HandlerMapping(处理器映射) ↓ Controller(控制器) ↓ Service(业务层) ↓ Dao(数据访问层) ↓ 返回ModelAndView ↓ ViewResolver(视图解析器) ↓ 返回视图给客户端
|
5.2 Spring MVC处理流程
5.3 常用注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| @Controller public class UserController {}
@RestController public class UserRestController {}
@RequestMapping("/users") @GetMapping("/users/{id}") @PostMapping("/users") @PutMapping("/users/{id}") @DeleteMapping("/users/{id}")
@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) {}
@GetMapping("/users") public List<User> list(@RequestParam(required = false) String name) {}
@PostMapping("/users") public User create(@RequestBody User user) {}
@ResponseBody public User getUser() {}
@ModelAttribute public void addAttributes(Model model) {}
|
六、Spring Boot
6.1 Spring Boot的优势
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @SpringBootApplication public class Application {}
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
@Configuration public class MyConfig {}
|
6.2 自动配置原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
@Configuration @ConditionalOnClass(DataSource.class) public class DataSourceAutoConfiguration { @Bean @ConditionalOnMissingBean public DataSource dataSource() { return new HikariDataSource(); } }
|
6.3 常用Starter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
|
七、面试高频问题
7.1 Spring和Spring Boot的区别?
| 特性 |
Spring |
Spring Boot |
| 配置 |
大量XML/注解配置 |
自动配置 |
| 依赖管理 |
手动管理版本 |
Starter统一管理 |
| 服务器 |
需要外部容器 |
内嵌容器 |
| 开发效率 |
较低 |
高 |
7.2 BeanFactory和ApplicationContext的区别?
- BeanFactory:Spring的基础容器,延迟加载
- ApplicationContext:功能更强大,立即加载,支持事件、国际化等
7.3 Spring如何解决循环依赖?
通过三级缓存和early reference机制,但构造器注入无法解决。
总结
Spring核心要点:
- IOC:依赖注入、Bean生命周期、循环依赖
- AOP:动态代理、切面、通知类型
- 事务:传播行为、隔离级别、失效场景
- MVC:请求处理流程、常用注解
- Boot:自动配置、Starter、内嵌容器
参考资料