Skip to content

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. 生命周期

  1. 实例化(构造方法)。
  2. 属性赋值(DI,setter)。
  3. Aware 接口回调(如 BeanNameAware)。
  4. BeanPostProcessor.postProcessBeforeInitialization
  5. 初始化@PostConstruct / InitializingBean.afterPropertiesSet / init-method)。
  6. BeanPostProcessor.postProcessAfterInitialization —— AOP 代理就在这一步生成。
  7. 使用
  8. 销毁@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. 事务失效的常见场景(高频面试)

  1. 方法非 public(AOP 默认只代理 public)。
  2. 同类内部方法调用(没走代理对象,this 调用)。
  3. 异常被 try-catch 吞掉
  4. 抛出的异常类型不匹配(默认只回滚 RuntimeException,需 rollbackFor = Exception.class)。
  5. Bean 不是 Spring 管理的
  6. 数据库不支持事务(如 MyISAM 引擎)。

练习建议

  1. 用注解方式搭建一个最小 IoC:@Service + @Autowired
  2. 写一个日志切面,统计 service 层所有方法耗时。
  3. 实现转账案例,加 @Transactional,故意抛异常观察回滚。
  4. 故意制造一个事务失效场景(如同类调用),并修复。
  5. (拓展)用 @EnableAspectJAutoProxy(exposeProxy = true) + AopContext.currentProxy() 解决同类调用失效。