02-Spring 核心(IoC 与 AOP)
对应原始资料:
spring-day01~day03
一、Spring 是什么
Spring 是 JavaEE 开发的一站式轻量级框架,两大核心:
- IoC / DI:控制反转 / 依赖注入 —— 对象创建与组装交给 Spring。
- AOP:面向切面编程 —— 在不修改源码的情况下增强功能。
二、IoC(控制反转)
1. 核心思想
传统写法:UserDao dao = new UserDaoImpl(); —— 对象由使用者自己 new,耦合。 IoC 写法:对象的创建交给 Spring 容器,使用者只负责"要"。
"控制反转":对象创建的控制权从程序反转到了 Spring 容器。
2. IoC 容器核心接口
BeanFactory ← IoC 顶层接口(懒加载)
└── ApplicationContext ← 常用(预加载)
├── ClassPathXmlApplicationContext XML 配置
├── FileSystemXmlApplicationContext
└── AnnotationConfigApplicationContext 注解配置三、XML 方式入门(理解原理)
1. 配置 bean
xml
<beans>
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
</beans>2. 获取
java
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = ctx.getBean("userService", UserService.class);3. DI 注入方式
- setter 注入(property):要求有无参构造 + setter。
- 构造方法注入(constructor-arg)。
- 自动装配 autowire="byType/byName"。
四、注解方式(实际开发主流)
1. 声明 Bean 的注解(组件标注)
| 注解 | 用在哪 | 说明 |
|---|---|---|
@Component | 通用 | 任意组件 |
@Controller | 表现层 | web 层 |
@Service | 业务层 | service 层 |
@Repository | 数据层 | dao 层 |
2. 注入 Bean 的注解
| 注解 | 说明 |
|---|---|
@Autowired | 按类型注入(Spring 提供,可加在字段/setter/构造) |
@Qualifier("xxx") | 配合 @Autowired 按名称注入 |
@Resource(name="xxx") | JDK 提供,按名称注入 |
@Value("${key}") | 注入普通值/配置文件值 |
3. 配置类替代 XML
java
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({OtherConfig.class})
public class SpringConfig { }获取:
java
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);五、Bean 的作用域与生命周期
1. 作用域(scope)
| scope | 说明 |
|---|---|
| singleton(默认) | 单例,整个容器一个实例 |
| prototype | 多例,每次 getBean 新建 |
| request | 每个 HTTP 请求一个(Web) |
| session | 每个会话一个(Web) |
2. 生命周期
- 实例化(构造方法)。
- 属性赋值(DI,setter)。
- Aware 接口回调(如 BeanNameAware)。
- BeanPostProcessor.postProcessBeforeInitialization。
- 初始化(
@PostConstruct/InitializingBean.afterPropertiesSet/init-method)。 - BeanPostProcessor.postProcessAfterInitialization —— AOP 代理就在这一步生成。
- 使用。
- 销毁(
@PreDestroy/DisposableBean.destroy/destroy-method)。
经典面试题:Bean 的生命周期完整有 7~9 步,重点是「实例化 → 属性填充 → 初始化 → 销毁」。
六、循环依赖
- A 依赖 B,B 依赖 A。
- Spring 用三级缓存解决 singleton 的循环依赖(构造方法循环依赖无法解决)。
- 三级缓存:
singletonObjects(成品)、earlySingletonObjects(半成品)、singletonFactories(工厂)。
七、AOP(面向切面编程)
1. 是什么
在不修改源码的前提下,对方法进行增强(前置、后置、环绕、异常、最终)。 应用:事务、日志、权限、缓存、性能监控。
2. 核心术语
| 术语 | 说明 |
|---|---|
| Target | 被代理的目标对象 |
| JoinPoint | 连接点,可以被增强的方法 |
| Pointcut | 切入点,真正被增强的方法 |
| Advice | 通知,增强的逻辑 |
| Aspect | 切面,Pointcut + Advice |
| Weaving | 织入,生成代理的过程 |
3. 通知类型
- 前置
@Before - 后置
@AfterReturning - 环绕
@Around - 异常
@AfterThrowing - 最终
@After
4. 入门示例
java
@Component
@Aspect
public class LogAspect {
// 切入点:service 包下所有方法
@Pointcut("execution(* com.itheima.service..*.*(..))")
public void pt() {}
@Before("pt()")
public void before(JoinPoint jp) {
System.out.println("【日志】调用 " + jp.getSignature());
}
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 执行目标方法
System.out.println("耗时 " + (System.currentTimeMillis() - start));
return result; // 必须返回
}
}启用 AOP:
java
@Configuration
@EnableAspectJAutoProxy // 开启 AOP
@ComponentScan("com.itheima")
public class AppConfig { }5. 切入点表达式
execution(修饰符 返回值 包.类.方法(参数))execution(* com.itheima.service.*.*(..)):service 包任意方法execution(* save*(..)):所有 save 开头方法
@annotation(com.itheima.anno.Log):标注了 @Log 注解的方法within(com.itheima..*):包内bean(userService):按 Bean 名称
6. AOP 底层原理
- 有接口:JDK 动态代理。
- 无接口:CGLIB 字节码增强。
- SpringBoot 2.x 起默认 CGLIB(即使有接口)。
八、Spring 事务
1. 编程式 vs 声明式
- 编程式:
TransactionTemplate.execute(...),灵活但侵入。 - 声明式(推荐):
@Transactional注解,AOP 实现。
2. @Transactional 使用
java
@Service
public class UserServiceImpl {
@Transactional
public void transfer(Integer from, Integer to, Double money) { ... }
}XML 或注解开启事务管理:
java
@EnableTransactionManagement
@Bean
public DataSourceTransactionManager txManager(DataSource ds) {
return new DataSourceTransactionManager(ds);
}3. 事务传播行为(propagation)
| 行为 | 说明 |
|---|---|
| REQUIRED(默认) | 有就加入,没有就新建 |
| REQUIRES_NEW | 总是新建,挂起当前 |
| SUPPORTS | 有就加入,没有就非事务 |
| NESTED | 嵌套事务(保存点) |
| MANDATORY / NEVER / NOT_SUPPORTED | 必须有 / 不能有 / 挂起 |
4. 隔离级别(isolation)
对应数据库的 4 个级别,默认 DEFAULT(用数据库的)。
5. 事务失效的常见场景(高频面试)
- 方法非 public(AOP 默认只代理 public)。
- 同类内部方法调用(没走代理对象,this 调用)。
- 异常被 try-catch 吞掉。
- 抛出的异常类型不匹配(默认只回滚
RuntimeException,需rollbackFor = Exception.class)。 - Bean 不是 Spring 管理的。
- 数据库不支持事务(如 MyISAM 引擎)。
练习建议
- 用注解方式搭建一个最小 IoC:
@Service+@Autowired。 - 写一个日志切面,统计 service 层所有方法耗时。
- 实现转账案例,加
@Transactional,故意抛异常观察回滚。 - 故意制造一个事务失效场景(如同类调用),并修复。
- (拓展)用
@EnableAspectJAutoProxy(exposeProxy = true)+AopContext.currentProxy()解决同类调用失效。