当前位置: 首页 > article >正文

Spring 核心指南(上):IoC 容器与配置方式详解

Spring 核心指南(上):IoC 容器与配置方式详解

在Java开发领域,Spring框架 是一种极为流行的企业级开源框架,以其轻量、易扩展和模块化的特性受到了广泛的欢迎。Spring框架的核心目标是简化Java开发,通过提供基础设施支持,让开发人员专注于业务逻辑的实现。Spring框架的核心模块之一是Spring IoC(Inversion of Control)容器,它是实现**依赖注入(DI, Dependency Injection)**的基础。

本文将对Spring框架做一个简要介绍,随后深入探讨IoC的概念、Spring IoC容器的原理及其实现方式。


一、Spring框架简介

1.1 Spring 与 Spring Framework 的概念

  • Spring Framework:指的是 Spring 开源项目的核心框架,提供了用于开发企业级Java应用的各种模块和组件。它是Spring生态的基础,主要包括IoC容器、AOP、数据访问、事务管理、Web MVC等功能模块。
  • Spring:在广义上可以指整个Spring生态系统,包括Spring Framework以及其他重要的子项目,例如Spring Boot、Spring Cloud、Spring Security等。Spring不仅是一个框架,更是一个庞大的技术栈,涵盖了从单体应用开发到微服务、云原生等领域的完整解决方案。

简单来说Spring Framework 是 Spring 技术栈的基础核心,而 Spring 通常是对整个生态的泛称。


二、Spring Framework 核心模块

Spring Framework 作为一个模块化的开源框架,为Java开发提供了依赖注入(IoC)面向切面编程(AOP)数据访问支持Web开发支持等核心功能。以下以表格形式列出Spring Framework的核心模块及其功能简介,并说明其与IoC容器的关联。

模块类型模块名称功能简介与IoC容器的关系
核心容器Core提供IoC和依赖注入功能,是Spring Framework的基础模块IoC容器的核心,实现依赖注入和Bean管理
Beans负责配置、创建和管理Bean对象提供Bean定义、Bean生命周期管理和依赖注入功能
Context提供ApplicationContext接口,实现上下文管理及资源访问继承自BeanFactory,提供更高级的IoC容器功能,例如国际化支持
Expression Language (SpEL)提供对属性、方法调用和复杂表达式的动态解析支持在IoC容器中支持通过表达式配置Bean属性
AOPAOP模块提供面向切面编程功能,用于实现横切关注点,如日志、事务等与IoC容器集成,通过AOP动态为Bean对象增强功能
数据访问JDBC模块简化JDBC操作,提供事务管理和异常处理通过IoC容器注入数据源、事务管理器和JDBC模板,提高数据访问的灵活性
ORM模块提供对Hibernate、JPA、MyBatis等ORM框架的支持IoC容器管理ORM框架的SessionFactory等对象
WebWeb模块提供Web应用开发的基础功能IoC容器管理Controller、Service等Web组件
Web MVC提供MVC设计模式的Web框架,用于构建前后端交互的Web应用IoC容器管理Controller、ViewResolver等Bean
WebFlux支持非阻塞式、反应式编程的Web框架IoC容器管理Reactive Controller和Reactive Service等组件
安全模块Security模块提供身份认证和授权机制IoC容器管理用户权限服务、认证组件
测试模块Test模块提供单元测试和集成测试的支持IoC容器在测试环境中注入模拟对象和测试用Bean

SpringFramework框架结构图:

在这里插入图片描述


三、Spring Framework 核心组件与 IoC 容器的关系

3.1 IoC 容器在 Spring 中的核心作用

**IoC(Inversion of Control,控制反转)*是Spring Framework的核心设计理念之一。**IoC容器** 是Spring Framework的核心组件,负责*Bean的创建、配置和管理,帮助开发者实现模块之间的低耦合依赖。在Spring的核心容器模块中,CoreBeansContext 模块紧密协作,共同实现 IoC 容器的功能。

  • BeanFactory:最基本的 IoC 容器接口,提供基础的 Bean 加载、创建和依赖注入功能。
  • ApplicationContextBeanFactory 的扩展接口,提供更多高级功能,例如事件发布、国际化和AOP支持。

Spring IoC 容器

Spring IoC 容器使用多种形式的配置元数据。此配置元数据表示您作为应用程序开发人员如何告诉 Spring 容器实例化、配置和组装应用程序中的对象。

在这里插入图片描述

3.2 Spring IoC / DI概念总结

  • IoC容器

    Spring IoC 容器,负责实例化、配置和组装 bean(组件)。容器通过读取配置元数据来获取有关要实例化、配置和组装组件的指令。

  • IoC(Inversion of Control)控制反转

    IoC 主要是针对对象的创建和调用控制而言的,也就是说,当应用程序需要使用一个对象时,不再是应用程序直接创建该对象,而是由 IoC 容器来创建和管理,即控制权由应用程序转移到 IoC 容器中,也就是“反转”了控制权。这种方式基本上是通过依赖查找的方式来实现的,即 IoC 容器维护着构成应用程序的对象,并负责创建这些对象。

  • DI (Dependency Injection) 依赖注入

    DI 是指在组件之间传递依赖关系的过程中,将依赖关系在容器内部进行处理,这样就不必在应用程序代码中硬编码对象之间的依赖关系,实现了对象之间的解耦合。在 Spring 中,DI 是通过 XML 配置文件或注解的方式实现的。它提供了三种形式的依赖注入:构造函数注入、Setter 方法注入和接口注入。

3.3 IoC容器如何与其他模块集成

  • AOP 模块:IoC容器通过将切面对象(Aspect)动态注入到Bean中,实现日志、事务等横切关注点的增强。
  • 数据访问模块:IoC容器为Service层注入数据源、事务管理器和DAO对象,实现数据访问逻辑的无缝集成。
  • Web 模块:IoC容器管理Controller、Service和Repository对象,将用户请求从Controller层传递到业务逻辑层,实现MVC架构的解耦。

四、Spring IoC / DI 实现

4.1 Spring IoC / DI 实现步骤


1. 基于注解的 IoC/DI 实现步骤

步骤 1:创建组件类

需要注入的对象通常是 POJO(Plain Old Java Object),并使用 Spring 提供的注解 @Component@Repository@Service 等来标识,将其交由 Spring 容器管理。

示例:

import org.springframework.stereotype.Repository;

@Repository  // 标识为一个 Bean,交由 Spring 容器管理
public class UserRepository {
    public void save(String username) {
        System.out.println("保存用户:" + username);
    }
}

步骤 2:定义依赖类并注入

在依赖类中,通过 @Autowired 注解进行依赖注入。

示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service  // 标识为 Service 层组件
public class UserService {

    private UserRepository userRepository;

    @Autowired  // 通过构造函数注入
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String username) {
        userRepository.save(username);
        System.out.println("用户注册成功");
    }
}

步骤 3:创建配置类

Spring 需要一个配置类,用来告诉 IoC 容器扫描哪些包下的 Bean。

示例:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration  // 标记为配置类
@ComponentScan(basePackages = "com.example")  // 扫描 com.example 包下的组件
public class AppConfig {
}

步骤 4:创建 IoC 容器并启动应用

通过 AnnotationConfigApplicationContext 创建容器并加载配置类。

示例:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        // 创建 Spring 容器并加载配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 UserService Bean 并调用方法
        UserService userService = context.getBean(UserService.class);
        userService.registerUser("张三");
    }
}

输出结果:

保存用户:张三  
用户注册成功

2. 基于 XML 配置的 IoC/DI 实现步骤

步骤 1:创建组件类

示例:

public class UserRepository {
    public void save(String username) {
        System.out.println("保存用户:" + username);
    }
}

步骤 2:定义依赖类

通过 set 方法注入依赖。

示例:

public class UserService {

    private UserRepository userRepository;

    // Setter 方法注入
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String username) {
        userRepository.save(username);
        System.out.println("用户注册成功");
    }
}

步骤 3:创建 XML 配置文件

applicationContext.xml 文件中定义 Bean 及其依赖关系。

示例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 定义 UserRepository Bean -->
    <bean id="userRepository" class="com.example.UserRepository"/>

    <!-- 定义 UserService Bean,并通过 setter 注入 userRepository -->
    <bean id="userService" class="com.example.UserService">
        <property name="userRepository" ref="userRepository"/>
    </bean>
</beans>

步骤 4:创建 IoC 容器并启动应用

使用 ClassPathXmlApplicationContext 加载 XML 配置文件。

示例:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        // 加载 XML 配置文件,创建 IoC 容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 获取 UserService Bean
        UserService userService = (UserService) context.getBean("userService");
        userService.registerUser("李四");
    }
}

输出结果:

保存用户:李四  
用户注册成功

3. 基于 Java 配置类的 IoC/DI 实现步骤

Spring 还支持通过 Java 配置类显式声明 Bean,采用 @Configuration@Bean 注解完成 Bean 的创建与注入。相比注解扫描和 XML 配置,这种方式更加灵活,适用于复杂应用场景。

步骤 1:创建组件类

创建普通的 Java 类,不需要使用 @Component@Repository 等注解。

示例:

public class UserRepository {
    public void save(String username) {
        System.out.println("保存用户:" + username);
    }
}

步骤 2:定义依赖类

同样创建普通 Java 类,通过构造函数注入依赖。

示例:

public class UserService {

    private UserRepository userRepository;

    // 构造函数注入
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void registerUser(String username) {
        userRepository.save(username);
        System.out.println("用户注册成功");
    }
}

步骤 3:创建 Java 配置类

在 Java 配置类中使用 @Configuration 标注该类为配置类,使用 @Bean 注解注册 Bean,并在方法中显式声明 Bean 之间的依赖关系。

示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration  // 标识该类为配置类
public class AppConfig {

    @Bean  // 注册 UserRepository Bean
    public UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean  // 注册 UserService Bean,并注入 UserRepository
    public UserService userService() {
        return new UserService(userRepository());
    }
}

步骤 4:创建 IoC 容器并启动应用

使用 AnnotationConfigApplicationContext 加载 Java 配置类,创建 IoC 容器并获取 Bean。

示例:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        // 加载配置类,创建 IoC 容器
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 UserService Bean
        UserService userService = context.getBean(UserService.class);
        userService.registerUser("王五");
    }
}

输出结果:

保存用户:王五  
用户注册成功

3. DI 方式比较与推荐

方式优点缺点推荐场景
构造函数注入依赖项不可变,强制依赖传入构造函数参数过多时显得复杂推荐:强依赖场景
Setter 注入依赖项可选,可部分注入无法强制传入所有依赖推荐:可选依赖场景
接口注入灵活性强侵入性强,不利于维护不推荐

4. 注意事项与最佳实践

  1. 优先使用注解配置:相比 XML 配置,注解方式更简洁、可读性更高,便于维护。
  2. 构造函数注入优先:构造函数注入可以避免对象依赖未被注入就被使用的问题,提高对象的不可变性。
  3. 避免循环依赖:Spring 无法自动解决构造函数循环依赖问题,可以通过重构代码或使用 @Lazy 解决。
  4. 模块化管理:保持良好的包结构和模块化配置,如 controllerservicerepository 等,利于开发和调试。

4. DI 方式比较与推荐

方式优点缺点推荐场景
构造函数注入依赖项不可变,强制依赖传入构造函数参数过多时显得复杂推荐:强依赖场景
Setter 注入依赖项可选,可部分注入无法强制传入所有依赖推荐:可选依赖场景
接口注入灵活性强侵入性强,不利于维护不推荐
Java 配置类注入配置灵活、依赖关系显式声明配置类 Bean 方法增多会臃肿推荐:复杂项目、条件配置

5. 注意事项与最佳实践

  1. 优先使用注解配置:注解配置相比 XML 配置更简洁,便于维护和扩展。
  2. 构造函数注入优先:构造函数注入可以提高对象的不可变性,避免未初始化依赖的使用问题。
  3. 避免循环依赖:构造函数注入无法自动解决循环依赖问题,可以通过 @Lazy 注解或重构类结构来避免。
  4. 模块化管理配置类:对于较大项目,可以将配置类按模块划分,例如 ControllerConfigServiceConfigRepositoryConfig 等,利于维护。
  5. 条件化配置:在 Java 配置类中可以根据环境参数或业务逻辑条件注册不同的 Bean(例如使用 @Conditional 注解)。

6. Spring IoC/DI 高级特性:FactoryBean 特性

FactoryBean 是 Spring 提供的一个特殊接口,用于自定义 Bean 的创建逻辑。它可以用来创建复杂类型的 Bean,而不仅仅是简单的实例化。通过 FactoryBean 接口,可以让开发者完全掌控对象的生成方式,甚至可以在生成的过程中加入缓存、代理、资源加载等自定义操作。


6.1 FactoryBean 概述

  • FactoryBean 接口是Spring IoC容器实例化逻辑的可插拔性点。

    用于配置复杂的Bean对象,可以将创建过程存储在FactoryBean 的getObject方法!

    FactoryBean<T> 接口提供三种方法:

    • T getObject():

      返回此工厂创建的对象的实例。该返回值会被存储到IoC容器!

    • boolean isSingleton():

      如果此 FactoryBean 返回单例,则返回 true ,否则返回 false 。此方法的默认实现返回 true (注意,lombok插件使用,可能影响效果)。

    • Class<?> getObjectType(): 返回 getObject() 方法返回的对象类型,如果事先不知道类型,则返回 null

    在这里插入图片描述


6.2 FactoryBean 使用场景

  • 复杂对象创建:如通过读取配置文件、连接外部资源创建对象等。
  • Bean 代理生成:如动态代理、AOP 场景中使用 FactoryBean 创建代理对象。
  • 条件化创建:根据运行时的条件创建不同实现的 Bean。

6.3 FactoryBean 的实现方法

步骤 1:创建目标类

例如,我们需要创建一个复杂的 User 对象:

public class User {
    private String username;

    public User(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" + "username='" + username + '\'' + '}';
    }
}

步骤 2:实现 FactoryBean 接口

创建一个 UserFactoryBean 实现 FactoryBean 接口,负责返回 User 实例。

示例代码:

import org.springframework.beans.factory.FactoryBean;

public class UserFactoryBean implements FactoryBean<User> {

    private String username;

    // 提供自定义属性用于配置
    public void setUsername(String username) {
        this.username = username;
    }

    // 返回 User 实例
    @Override
    public User getObject() throws Exception {
        return new User(username);  // 创建并返回一个 User 实例
    }

    // 返回 User 类型
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return true;  // 表示该 FactoryBean 生成的 Bean 是单例
    }
}

步骤 3:在配置类中注册 FactoryBean

通过 @BeanUserFactoryBean 注册为 Spring 容器中的 Bean。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public UserFactoryBean userFactoryBean() {
        UserFactoryBean factoryBean = new UserFactoryBean();
        factoryBean.setUsername("张三");
        return factoryBean;
    }
}

步骤 4:获取 FactoryBean 管理的对象

在主类中获取 User 实例。

示例:

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 FactoryBean 创建的 User 实例
        User user = context.getBean(User.class);
        System.out.println(user);  // 输出:User{username='张三'}

        // 如果需要获取 FactoryBean 实例本身,需要在 Bean 名称前加上 "&"
        UserFactoryBean factoryBean = (UserFactoryBean) context.getBean("&userFactoryBean");
        System.out.println("FactoryBean 本身: " + factoryBean);
    }
}

输出结果:

User{username='张三'}  
FactoryBean 本身: com.example.UserFactoryBean@1a93a7ca

6.4 解释关键点

  • getObject():用于返回生成的目标 Bean。
  • getObjectType():指定生成对象的类型,Spring 容器可以根据类型进行类型匹配。
  • isSingleton():用于指定生成的 Bean 是否为单例。返回 true 表示生成的对象是单例,false 表示每次请求都生成新对象。
  • &userFactoryBean& 前缀用于获取 FactoryBean 本身,而不是 getObject() 返回的目标 Bean。

6.5 使用 FactoryBean 的高级应用

1. 动态代理对象

FactoryBean 可以用来创建动态代理对象,例如 JDK 动态代理或 CGLIB 代理。
示例场景:

public class ProxyFactoryBean implements FactoryBean<MyService> {
    @Override
    public MyService getObject() throws Exception {
        return (MyService) Proxy.newProxyInstance(
                MyService.class.getClassLoader(),
                new Class[]{MyService.class},
                (proxy, method, args) -> {
                    System.out.println("调用方法:" + method.getName());
                    return null;
                });
    }

    @Override
    public Class<?> getObjectType() {
        return MyService.class;
    }
}

2. 读取配置文件动态创建对象

示例场景:
通过 FactoryBean 读取外部配置文件(如 JSON 文件)创建 Bean:

public class ConfigurableUserFactoryBean implements FactoryBean<User> {

    private String configFilePath;

    public void setConfigFilePath(String configFilePath) {
        this.configFilePath = configFilePath;
    }

    @Override
    public User getObject() throws Exception {
        // 假设读取配置文件生成对象
        String username = new Scanner(new File(configFilePath)).nextLine();
        return new User(username);
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}

6.6 FactoryBean 使用注意事项

  1. 尽量避免滥用:如果对象的创建逻辑并不复杂,可以直接使用 @Component 进行注入,不必使用 FactoryBean
  2. Bean 命名冲突:使用 FactoryBean 时,& 符号用于获取工厂类本身,避免误用。
  3. 多态支持getObjectType() 返回的类型可以是接口类型,以便支持多态 Bean 注入。
FactoryBean和BeanFactory区别

    \*\*FactoryBean \*\*是 Spring 中一种特殊的 bean,可以在 getObject() 工厂方法自定义的逻辑创建Bean!是一种能够生产其他 Bean 的 Bean。FactoryBean 在容器启动时被创建,而在实际使用时则是通过调用 getObject() 方法来得到其所生产的 Bean。因此,FactoryBean 可以自定义任何所需的初始化逻辑,生产出一些定制化的 bean。

    一般情况下,整合第三方框架,都是通过定义FactoryBean实现!!!

    **BeanFactory** 是 Spring 框架的基础,其作为一个顶级接口定义了容器的基本行为,例如管理 bean 的生命周期、配置文件的加载和解析、bean 的装配和依赖注入等。BeanFactory 接口提供了访问 bean 的方式,例如 getBean() 方法获取指定的 bean 实例。它可以从不同的来源(例如 Mysql 数据库、XML 文件、Java 配置类等)获取 bean 定义,并将其转换为 bean 实例。同时,BeanFactory 还包含很多子类(例如,ApplicationContext 接口)提供了额外的强大功能。

    总的来说,FactoryBean 和 BeanFactory 的区别主要在于前者是用于创建 bean 的接口,它提供了更加灵活的初始化定制功能,而后者是用于管理 bean 的框架基础接口,提供了基本的容器功能和 bean 生命周期管理。

6.7 总结

FactoryBean 是 Spring 提供的用于自定义 Bean 创建逻辑的接口,适用于复杂对象创建动态代理资源加载等场景。在使用时,可以通过 getObject() 返回具体的目标 Bean,而在特殊情况下使用 & 符号获取 FactoryBean 本身。合理使用 FactoryBean 能增强 Spring 容器的灵活性,但在简单场景中不建议过度使用,以免增加系统复杂度。

7. 高级特性:Bean 的作用域

Spring 提供了多种作用域来管理 Bean 的生命周期和可见范围。


7.1 作用域类型

作用域类型描述常见应用场景
singleton(默认值)每个 Spring 容器中只创建一个实例,所有请求返回同一个实例。无状态的 Service 或工具类
prototype每次请求都会创建一个新的实例。需要生成多个对象时
request每个 HTTP 请求创建一个实例,仅限于 Web 应用。Web 应用中的 Controller Bean
session每个 HTTP 会话创建一个实例,仅限于 Web 应用。保存与用户会话相关的 Bean
application每个 ServletContext 共享一个实例,仅限于 Web 应用。全局共享的 Bean
websocket每个 WebSocket 会话共享一个实例。WebSocket 应用

7.2 Bean 作用域示例

1. 单例(Singleton)

@Service
public class SingletonService {
    public SingletonService() {
        System.out.println("创建单例实例");
    }
}

示例:

SingletonService s1 = context.getBean(SingletonService.class);
SingletonService s2 = context.getBean(SingletonService.class);
System.out.println(s1 == s2);  // 输出 true

2. 多实例(Prototype)

@Component
@Scope("prototype")
public class PrototypeService {
    public PrototypeService() {
        System.out.println("创建多实例对象");
    }
}

8. 高级特性:Bean 的生命周期


8.1 生命周期流程

在这里插入图片描述

 Spring Bean 的生命周期指从 Spring 容器创建 Bean 实例开始,到 Bean 销毁的整个过程,可以按照以下流程分为以下几个阶段:
    1.  实例化Bean实例:Spring 容器使用指定的实例化策略创建 bean,该策略可以是无参构造、工厂方法等。当 Spring 加载 Bean 的配置文件并且 Bean 标签被解析后,这个类(Bean)就会被实例化。
    2.  Bean实例属性设置:Spring 通过调用 setter 方法或直接设置字段的方式来注入 Bean 的属性。
    3.  Aware 相关接口的回调:Spring 通过 Aware 接口来把一些 Bean 相关的资源注入到 Bean 中。例如,BeanNameAware 接口可获取到 Bean 的名称;ApplicationContextAware 接口可获取到 ApplicationContext 对象实例;BeanFactoryAware 接口可获取到 BeanFactory 对象实例等。
    4.  Bean初始化前的操作:在 Bean 的初始化之前,Spring 允许用户自定义 Bean 实例化后的一些操作。
        -   如果有BeanPostProcessor注册,先执行beforeInitialization()方法;
        -   如果Bean实现了InitializingBean接口,则执行afterPropertiesSet()方法
    5.  Bean 的初始化方法调用:如果在配置文件中使用init-method属性声明了初始化方法,则执行该方法;
    6.  Bean初始化后的操作:在 Bean 的初始化之后,如果有BeanPostProcessors注册,执行afterInitialization()方法;

        此方法中,Bean实例已经完成了实例化和初始化工作,最终会将afterInitialization()方法修改后返回的对象存储到IoC容器中!

        Spring Aop的实现,通过定义BeanPostProcessor(AbstractAutoProxyCreator),在后置方法中添加动态代理技术,进行Bean的动态代理对象生成!
    7.  使用 Bean:即在 IoC 容器中调用 getBean() 方法获取 Bean 实例,使用 Bean 的过程。
    8.  销毁 Bean:当 Bean 不再被使用时,Spring 容器会自动释放 Bean 占有的资源,关闭 IoC 容器。 开发人员可以自己实现 DisposableBean 接口或者为 Bean 配置一个指定的 destroy-method 方法来实现自定义销毁的逻辑。
    9.  关闭IoC容器
        在整个生命周期过程中,Spring 提供了各种监听器和钩子函数,允许开发人员在不同的 Bean 生命周期阶段添加自己的处理逻辑以实现更加灵活和智能的控制。

8.2 生命周期回调方法

方式描述
实现 InitializingBean 接口通过实现 afterPropertiesSet() 方法来进行初始化逻辑。
使用 @PostConstruct 注解初始化时调用的方法,推荐使用这种方式。
配置 initMethod在 XML 或 @Bean 注解中指定初始化和销毁方法。
实现 DisposableBean 接口通过实现 destroy() 方法定义销毁逻辑。
使用 @PreDestroy 注解在 Bean 销毁之前执行的方法,推荐使用这种方式。

8.3 生命周期示例

1. 使用 @PostConstruct@PreDestroy 注解

@Component
public class LifecycleBean {

    @PostConstruct
    public void init() {
        System.out.println("初始化方法");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("销毁方法");
    }
}

五、三种配置方式总结

在 Spring IoC 容器中,Bean 的定义和管理可以通过以下三种配置方式来实现:XML 配置、XML + 注解混合配置、完全注解配置。本节对这三种配置方式进行总结和对比,帮助你选择合适的配置方案。


5.1 XML 配置方式

特点:
所有配置都写在 XML 文件中,包含 Bean 定义、依赖注入、外部配置文件引入等。

总结:

  1. Bean 声明:使用 标签声明 Bean。

    <bean id="userService" class="com.example.UserService">
        <property name="userRepository" ref="userRepository"/>
    </bean>
    
  2. 属性注入:通过 <property> 标签设置属性值或对象引用。

  3. 引入外部配置文件:使用 context:property-placeholder 引入 properties 文件。

    <context:property-placeholder location="classpath:application.properties"/>
    
  4. 启用 IoC 容器:使用 ClassPathXmlApplicationContext 加载配置文件。

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    

优点

  • 配置集中、直观,所有 Bean 定义可在 XML 文件中一目了然。

缺点

  • XML 配置较繁琐,可读性差,容易出错。

5.2 XML + 注解混合配置方式

特点:
结合 XML 和注解,利用 XML 文件定义扫描范围和外部配置文件,同时用注解简化 Bean 声明。

总结:

  1. 组件扫描范围:在 XML 文件中使用 context:component-scan标签定义扫描范围。

    <context:component-scan base-package="com.example"/>
    
  2. IoC 注解:

    • 标记 IoC 组件:@Component@Service@Controller@Repository
    • 标记 DI 注解:@Autowired@Qualifier@Resource@Value
  3. 引入外部配置文件:通过 <context:property-placeholder> 引入 properties 文件。

  4. 启用 IoC 容器:同样使用

    ClassPathXmlApplicationContext
    

    加载配置文件。

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    

优点

  • 结合 XML 配置的集中性和注解的简洁性。

缺点

  • XML 和注解混用,项目结构可能显得复杂,需要同时维护两种配置形式。

5.3 完全注解配置方式

特点:
完全去掉 XML 文件,通过 Java 配置类和注解实现 Bean 定义和依赖注入。

总结:

  1. Java 配置类:使用

    @Configuration
    

    注解标记配置类,取代 XML 文件。

    @Configuration
    @ComponentScan(basePackages = "com.example.components")
    public class AppConfig {
    }
    
  2. 依赖注入注解:

    • 标记 IoC 组件:@Component@Service@Controller@Repository
    • 标记 DI 注解:@Autowired@Qualifier@Resource@Value
  3. 引入外部配置文件:使用

    @PropertySource
    

    注解替代

    <context:property-placeholder>
    
    @PropertySource({"classpath:application.properties"})
    
  4. Bean 创建使用 @Bean

    注解方法创建自定义 Bean。

    @Bean
    public DataSource dataSource() {
        return new HikariDataSource();
    }
    
  5. 启用 IoC 容器使用 AnnotationConfigApplicationContext加载 Java 配置类。

    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    

优点

  • 配置方式灵活,完全基于 Java 代码,可避免 XML 配置带来的冗余和易错问题。

缺点

  • 需要对注解和 Java 配置类较为熟练,Bean 数量较多时,配置类可能较为臃肿。

5.4 配置方式对比

配置方式配置形式IoC 容器优点缺点适用场景
XML 配置纯 XML 配置文件ClassPathXmlApplicationContext配置集中显式可见,便于查看所有配置配置冗长、可读性差传统项目、需要集中配置场景
XML + 注解XML 定义扫描范围,注解标记组件ClassPathXmlApplicationContext注解简化 Bean 声明,保留 XML 的集中性需要同时维护 XML 文件和注解配置渐进式从 XML 向注解过渡的项目
完全注解纯 Java 配置类 + 注解AnnotationConfigApplicationContext无 XML 文件,代码简洁灵活配置类数量多时容易臃肿新项目、需要无 XML 配置的场景

http://www.kler.cn/a/501744.html

相关文章:

  • ubuntu22.4 ROS2 安装gazebo(环境变量配置)
  • HBuilderX打包ios保姆式教程
  • 反转链表题目
  • SQL分类与数据类型整理
  • 【Uniapp-Vue3】Prop校验与prop默认值用法及循环遍历数组对象
  • 抖音矩阵是什么
  • bert微调下游任务-情感分析
  • WRF模式与Python融合技术在多领域中的应用及精美绘图;Python助力WRF自动化运行、WRF模式前后处理等
  • 达梦8-DMSQL程序设计学习笔记1-DMSQL程序简介
  • ASP.NET Core 中,Cookie 认证在集群环境下的应用
  • c# 和python封装起保停
  • 功能篇:mybatis中实现缓存
  • JSON头文件调用
  • Fastapi0.115.6之Tortoise ORM0.23.0基本增删改查大全【亲测可用,仅供参考】
  • AIDD-人工智能药物设计-通过组合生物合成产生新的类似物的抗真菌费尔南型三萜多聚类素的生物合成表征
  • AI多模态论文解读:LLaVA-CoT:让视觉语言模型逐步推理
  • uni-app持久化登录简单实现
  • 八、系统托盘与配置面板
  • springmvc前端传参,后端接收
  • StarRocks Awards 2024 年度贡献人物
  • 《解锁鸿蒙系统AI能力,开启智能应用开发新时代》
  • 【GoLand】无法debug 无法运行
  • 【Orca】Orca - Graphlet 和 Orbit 计数算法
  • 《解锁计算机视觉智慧:编程实现图片场景文字描述的开源宝藏》
  • mysql-行溢出处理原理
  • 【HTML+CSS+JS+VUE】web前端教程-21-字体属性