Spring核心知识精讲:IoC容器、Bean作用域生命周期与AOP(第二部分)

本文将系统梳理Spring框架的几个核心概念,涵盖ApplicationContext与BeanFactory的区别、Bean的作用域与生命周期、基于注解的IoC/DI,以及AOP的原理与配置,旨在帮助开发者构建扎实的Spring基础。

一、ApplicationContext 与 BeanFactory 的区别

二者都是Spring IoC容器的核心接口,用于管理Bean的生命周期和依赖关系。

  • BeanFactory :IoC容器的顶级接口 。它采用了延迟加载策略,即在第一次调用getBean()方法获取对象时,才会实例化该Bean

  • ApplicationContext :它是BeanFactory子接口 ,在继承了其所有功能的基础上,增加了更多企业级特性(如国际化、事件发布等)。其关键区别在于,它采用了预加载(饿汉式)策略 ,在容器启动、加载配置文件时,就会创建并初始化所有的单例Bean

简单比喻BeanFactory是基础版工厂,按需生产;ApplicationContext是增强版工厂,开业前就备好了所有招牌产品,启动更耗时但运行时响应更快。在绝大多数现代Spring应用中,我们直接使用功能更强大的ApplicationContext

二、Spring Bean 的5个作用域

Spring为Bean定义了多种作用域,以适配不同的使用场景。

  1. 五种核心作用域

    • singleton ​ (默认):在Spring IoC容器中,一个Bean定义只对应一个实例 。所有对该Bean的请求都返回同一个共享对象。其本质是容器内部维护的一个Map

    • prototype :每次请求(调用getBean())时,Spring都会创建一个新的Bean实例 。其本质是每次调用newInstance()

    • request :每次HTTP请求都会创建一个新的Bean,仅适用于Web应用

    • session :在一个HTTP Session的生命周期内,一个Bean定义对应一个实例,仅适用于Web应用

    • application :在一个ServletContext的生命周期内,一个Bean定义对应一个实例,仅适用于Web应用

  2. 如何指定作用域

    在XML配置中,通过scope属性指定。

    复制代码
    <bean id="myBean" class="com.example.MyBean" scope="prototype"/>

    使用注解时,使用@Scope注解。

    复制代码
    @Component
    @Scope("prototype")
    public class MyPrototypeBean { }
  3. 单例与多例的使用场景

    • 使用单例(singleton) :无状态的、线程安全的对象。例如:各种ServiceDao、工具类、以及所有的工厂类(如SqlSessionFactory)。这是最常用的作用域。

    • 使用多例(prototype) :有状态的、非线程安全的对象。例如:数据库连接Connection、MyBatis的SqlSession(旧版)、每次交互需要独立状态的对象。

三、Spring Bean 的生命周期

Bean的生命周期指其从创建到销毁的整个过程,Spring允许我们在特定节点插入自定义逻辑。

  1. 生命周期关键方法示例

    我们可以通过配置init-methoddestroy-method来指定初始化和销毁时调用的方法。

    Bean类定义

    复制代码
    public class UserServiceImpl {
        public UserServiceImpl() {
            System.out.println("1. 调用构造方法实例化Bean...");
        }
        public void setDependency(...) {
            System.out.println("2. 调用set方法进行依赖注入...");
        }
        public void myInit() {
            System.out.println("3. 调用init-method进行自定义初始化...");
        }
        public void myDestroy() {
            System.out.println("5. 调用destroy-method进行自定义销毁...");
        }
    }

    XML配置

    复制代码
    <bean id="userService" class="com.hg.UserServiceImpl"
          init-method="myInit" destroy-method="myDestroy"/>
  2. 完整生命周期流程

    • 对于单例Bean(singleton)

      1. 启动容器 ​ -> 2. 调用构造方法 实例化 -> 3. 调用setter 注入依赖 -> 4. 调用init-method ​ -> [容器运行中] ​ -> 5. 关闭容器 ​ -> 6. 调用destroy-method

      单例Bean的初始化在容器启动时完成,销毁在容器关闭时进行。

    • 对于多例Bean(prototype)

      1. 调用getBean() ​ -> 2. 调用构造方法 实例化 -> 3. 调用setter 注入依赖 -> 4. 调用init-method ​ -> [返回对象给使用者] ​ -> 5. JVM垃圾回收 ​ -> 6. 容器不管理其销毁,destroy-method不会被Spring调用。

      多例Bean的初始化在每次获取时完成,其生命周期由JVM管理,Spring容器不负责销毁。

四、基于注解的 IoC 与 DI

注解极大地简化了Spring的配置。

  1. 配置步骤

    • 步骤1:在配置文件中启用组件扫描。

      复制代码
      <context:component-scan base-package="com.hg"/>
    • 步骤2 (IoC):在类上使用组件注解,将其声明为Spring Bean。

      复制代码
      @Repository // 等价于<bean id="userDaoImpl" class="...">
      public class UserDaoImpl implements UserDao { }
    • 步骤3 (DI):在需要依赖的字段/方法上使用自动装配注解。

      复制代码
      @Service
      public class UserServiceImpl implements UserService {
          @Autowired // 按类型自动查找并注入UserDao的Bean
          // @Resource(name="userDaoImpl") // 也可按名称注入
          private UserDao userDao;
      }
  2. 常用注解

    • IoC (Bean声明)

      • @Repository:标注数据访问层​ (DAO) 组件。

      • @Service:标注业务逻辑层​ (Service) 组件。

      • @Controller:标注控制层​ (Web Controller) 组件。

      • @Component:标注不属于以上三层的通用组件。

      • @Scope:指定Bean的作用域,如 @Scope("prototype")

    • DI (依赖注入)

      • @Autowired:Spring提供,默认按类型 (byType)注入。可配合@Qualifier指定名称。

      • @Resource:JSR-250规范,默认按名称 (byName)注入。name属性指定Bean id。

      • @Value:注入普通值(基本类型、String)或SpEL表达式,常用于注入配置文件属性。

五、AOP (面向切面编程)
  1. 为什么需要AOP?

    考虑为所有Service方法添加日志记录。若不使用AOP,需要在每个方法中手动添加日志代码,导致代码冗余维护困难、核心业务逻辑不清晰。

    复制代码
    public class Service {
        public void add() {
            System.out.println("方法开始:" + new Date()); // 重复的日志代码
            // ... 核心业务逻辑 ...
            System.out.println("方法结束:" + new Date()); // 重复的日志代码
        }
        // 其他每个方法都需要写一遍日志
    }

    AOP的目标就是将此类横切关注点(日志、事务、安全等)从业务逻辑中剥离出来。

  2. 什么是AOP?

    AOP (Aspect Oriented Programming) ​ 面向切面编程:一种编程范式,允许将程序中重复的代码(横切关注点)抽取 出来,形成独立的"切面",然后通过动态代理 技术,在不修改源代码的前提下,将切面逻辑织入到目标方法中,从而对程序功能进行增强。

  3. AOP的核心概念

    • 连接点 (Joinpoint) :程序执行过程中明确的点,如方法调用、异常抛出。在Spring AOP中,通常指方法的执行

    • 切点 (Pointcut) :一个表达式,用于匹配 一个或多个连接点(即,哪些方法需要被增强)。例如:execution(* com.hg.service.*.*(..))

    • 增强/通知 (Advice) :在切点处执行的具体逻辑(即,要"搞"的事情,如打印日志)。它定义了增强的时机(前置、后置等)和行为。

    • 切面 (Aspect)增强切点的结合。它定义了"在何处(切点)"执行"何种增强(通知)"。

  4. 五种通知类型及其执行顺序

    复制代码
    try {
        // 1. 前置通知 (@Before)
        // ... 执行目标方法 (Joinpoint) ...
        // 2. 后置/返回通知 (@AfterReturning) - 方法正常返回后执行
    } catch (Exception e) {
        // 3. 异常通知 (@AfterThrowing) - 方法抛出异常后执行
    } finally {
        // 4. 最终通知 (@After) - 类似于finally块,无论如何都执行
    }
    // 5. 环绕通知 (@Around) - 能控制目标方法是否执行,最强大。
  5. 基于XML的AOP配置

    复制代码
    <!-- 1. 定义增强(通知)Bean -->
    <bean id="logAdvice" class="com.hg.advice.LogAdvice"/>
    
    <!-- 2. 配置AOP -->
    <aop:config>
        <!-- 2.1 定义切点表达式 -->
        <aop:pointcut id="servicePointcut"
                      expression="execution(* com.hg.service.*.*(..))"/>
        <!-- 2.2 定义切面 -->
        <aop:aspect ref="logAdvice">
            <!-- 将增强应用到切点 -->
            <aop:before method="beforeLog" pointcut-ref="servicePointcut"/>
        </aop:aspect>
    </aop:config>
  6. 基于注解的AOP配置

    复制代码
    @Aspect  // 1. 声明这是一个切面类
    @Component // 2. 让Spring管理它
    public class LogAdvice {
        // 3. 定义切面:在何处执行何种增强
        @Before("execution(* com.hg.service.*.*(..))") // 切点表达式直接写在注解里
        public void beforeLog() {
            System.out.println("前置通知: " + new Date());
        }
    }

    在Spring配置文件中开启注解AOP支持:

    复制代码
    <aop:aspectj-autoproxy/>
  7. 切点表达式 (Pointcut Expression)

    格式:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

    • *代表通配符。

    • ..代表当前包及其子包,或代表任意参数。

    • 示例

      • execution(* com.hg.service.UserServiceImpl.addUser(..)):匹配UserServiceImpladdUser方法。

      • execution(* com.hg.service.UserServiceImpl.*(..)):匹配UserServiceImpl的所有方法。

      • execution(* com.hg.service.*.*(..)):匹配com.hg.service包下所有类的所有方法(最常用)。


总结 :本文从容器基础(BeanFactory/ApplicationContext)、Bean管理(作用域、生命周期)、便捷开发(注解IoC/DI)到核心思想(AOP)系统回顾了Spring框架的基石。理解这些概念是掌握Spring生态和进行高效Java企业开发的关键。

相关推荐
野生技术架构师2 小时前
Java面试精选:数据库 + 数据结构 +JVM+ 网络 +JAVA+ 分布式
java·数据库·面试
甲鱼9292 小时前
FreeSWITCH 对接 SIP 中继踩坑记录
后端·程序员
你这个代码我看不懂2 小时前
JVM栈、方法区和堆内存
java·开发语言·jvm
学编程就要猛2 小时前
JavaEE初阶:多线程案例
java·开发语言
执笔论英雄2 小时前
【cuda】 pinpaged
android·java·数据库
茶本无香2 小时前
【无标题】Kafka 系列博文(一):从零认识 Kafka,到底解决了什么问题?
java·分布式·kafka
星辰_mya2 小时前
Fork/Join 框架与并行流:CPU 密集型的“分身术”
java·开发语言·面试
惊讶的猫2 小时前
SpringMVC介绍
java·springmvc·springboot
JWASX2 小时前
【RocketMQ 生产者和消费者】- 事务消息的使用
java·rocketmq·java-rocketmq