Spring IOC/DI 核心知识点笔记

31 阅读3分钟

Spring IOC/DI 核心知识点笔记

一、核心概念

  1. IOC(控制反转) 对象的创建控制权从程序自身转移到外部 IOC 容器,由容器统一管理对象的创建,这种思想称为控制反转。
  2. DI(依赖注入) IOC 容器在程序运行时,主动为应用程序提供其依赖的资源(对象),这个过程称为依赖注入。
  3. Bean 对象由 IOC 容器创建、管理的对象,称之为 Bean。

二、自定义 Bean 的声明(@Component及衍生注解)

通过在类上添加注解,将自定义类交给 IOC 容器管理,共 4 种等价注解(功能一致,语义区分层):

  1. @Component:无法归类到其他层时使用
  2. @Controller:控制层类专用
  3. @Service:服务层类专用
  4. @Repository:数据访问层类专用(实际开发中使用较少)

补充说明

  • @RestController = @Controller + @ResponseBody(控制层返回 JSON 时用)
  • 上述注解生效的前提:被@ComponentScan(组件扫描)覆盖
  • @ComponentScan默认包含在@SpringBootApplication中,默认扫描范围是启动类所在包及其子包
  • 注意:@ComponentScan覆盖配置,不是追加配置

三、第三方 Bean 的声明(@Bean

1. 适用场景

当要管理的 Bean 来自第三方(如框架、工具类)时,因第三方类无法修改源码添加@Component,需用@Bean声明。

2. 核心规则

  • 功能:将方法的返回值对象交给 IOC 容器管理,成为容器中的 Bean。

  • Bean 名称规则:

    • 通过@Bean(name/value)指定名称;
    • 未指定时,默认以方法名作为 Bean 名称。

3. 第三方 Bean 的依赖注入

若第三方 Bean 依赖其他 Bean,直接在@Bean方法中加形参即可,容器会自动按类型注入依赖:

@Configuration
public class CommonConfig {
    // 第三方Bean(SAXReader)依赖自定义Bean(DeptService)
    @Bean
    public SAXReader reader(DeptService deptService) {
        System.out.println(deptService); // 依赖的Bean由容器自动注入
        return new SAXReader();
    }
}

4. 推荐配置方式(配置类集中管理)

为保证启动类纯粹性,建议用@Configuration声明配置类,集中管理第三方 Bean:

@Configuration // 标识为配置类
public class CommonConfig {
    // 示例1:默认以方法名“saxReader”为Bean名
    @Bean
    public SAXReader saxReader() {
        return new SAXReader();
    }

    // 示例2:通过name指定Bean名为“myHttpClient”
    @Bean(name = "myHttpClient")
    public HttpClient httpClient() {
        return HttpClientBuilder.create().build();
    }
}

5. 不推荐的方式(但是可行)

不要直接在启动类中声明@Bean(会导致启动类职责混乱):

@SpringBootApplication
public class SpringbootWebConfig2Application {
    // 不推荐!破坏启动类纯粹性
    @Bean
    public SAXReader saxReader() {
        return new SAXReader();
    }
}

四、IOC 容器中主动获取 Bean 的方式

1. 先获取 IOC 容器对象

通过@Autowired注入ApplicationContext(代表 IOC 容器):

@Autowired
private ApplicationContext applicationContext; // IOC容器对象

2. 三种获取 Bean 的方法

通过applicationContext调用以下方法:

  1. 根据名称获取方法:Object getBean(String name)说明:返回 Object 类型,需手动强转。
  2. 根据类型获取方法:<T> T getBean(Class<T> requiredType)说明:直接返回对应类型,但容器中同类型 Bean 只能有一个。
  3. 根据名称 + 类型获取(带转换) 方法:<T> T getBean(String name, Class<T> requiredType)说明:指定名称 + 类型,直接返回对应类型,无需强转。

五、Bean 的作用域与懒加载

1. 作用域分类

Spring 支持 5 种作用域,后 3 种仅在 Web 环境生效:

作用域说明
singleton容器内同名称 Bean 仅 1 个实例(单例)默认
prototype每次使用时创建新实例(非单例)
request每个 HTTP 请求内创建新实例(Web 环境)
session每个会话内创建新实例(Web 环境)
application每个应用内创建新实例(Web 环境)

2. 作用域配置

通过@Scope注解配置,例如:

@Component
@Scope("prototype") // 设置为非单例
public class UserService {}

3. 懒加载(@Lazy

  • 作用:默认singletonBean 在容器启动时创建,加@Lazy第一次使用时才创建
  • 适用场景:配合singleton使用。
  • prototype本身是懒加载的。

六、@Component@Bean的使用场景区分

注解类型使用场景
@Component及衍生注解项目中自定义的类
@Bean注解项目中引入第三方的类