Spring IOC 入门

一、IOC

IOC的全称是 Inversion of Control,中文翻译为 "控制反转",它是一种设计思想,核心是颠覆了传统的对象创建和依赖管理方式。

1.控制反转

"控制"在这里指的是对象的创建权、依赖的管理控制权。

传统方式(无IOC):

开发者在程序中直接 new 对象,手动管理所有依赖。比如你需要一个UserService,它依赖UserDao,你要自己创建:

java 复制代码
// 传统方式:开发者手动控制对象创建和依赖
public class UserService {
    // 手动创建依赖对象
    private UserDao userDao = new UserDaoImpl();
    
    public void addUser() {
        userDao.add();
    }
}

// 使用时还要手动创建UserService
public class Main {
    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.addUser();
    }
}

IOC方式(控制反转):

把对象的创建、依赖注入、生命周期管理等"控制权"反转给容器(比如Spring容器),开发者只需要定义"需要什么",而不用管"怎么创建"。

java 复制代码
// IOC方式:开发者只声明依赖,容器负责创建和注入
public class UserService {
    // 声明依赖,不手动创建
    private UserDao userDao;
    
    // 提供构造器/setter,让容器注入依赖
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
    
    public void addUser() {
        userDao.add();
    }
}

2.DI

DI(Dependency Injection,依赖注入):IOC的实现方式,容器将依赖关系注入到对象中。

核心含义:**"注入"**是指由外部实体(IOC容器)在创建对象时,将其所依赖的对象通过构造函数、Setter方法或接口等方式"传递"(注入)给它。

DI是实现IOC思想的具体技术手段。它明确了"反转"的具体方式:通过"注入"来提供依赖。

3.IOC容器(实现IOC/DI的框架组件)

IOC容器(在 Spring 中就是 ApplicationContext)是具体干活的角色。它的核心工作是:

  1. 创建和管理对象
  2. 管理对象的生命周期
  3. 自动注入依赖

4.IOC的优点

  1. 解耦:类与类之剑不再直接依赖
  2. 简化开发:无需手动管理对象的创建和依赖
  3. 便于测试:可以轻松替换依赖为模拟对象
  4. 统一管理:容器统一管理对象的生命周期

二、Spring IOC

Spring IOC 是 "IOC 思想" 的Java落地实现,Spring 框架把 IOC 思想变成了可以直接使用的工具(Spring IOC 容器)。

1.配置方式

1.1.XML配置(传统方式)

xml 复制代码
<!-- applicationContext.xml -->
<beans>
    <!-- 定义Bean -->
    <bean id="userService" class="com.example.UserServiceImpl">
        <!-- 属性注入 -->
        <property name="userDao" ref="userDao"/>
    </bean>
    
    <bean id="userDao" class="com.example.UserDaoImpl"/>
</beans>

1.2.注解配置(推荐)

java 复制代码
@Component  // 标识为Spring组件
public class UserServiceImpl implements UserService {
    
    @Autowired  // 自动注入依赖
    private UserDao userDao;

    public void addUser() {
        userDao.add();
    }
}

@Repository  // 数据访问层组件
public class UserDaoImpl implements UserDao {
    // ...
}

1.3.Java配置类

java 复制代码
@Configuration  // 声明为配置类
@ComponentScan("com.example")  // 扫描组件
@PropertySource("classpath:app.properties")  // 加载配置文件
public class AppConfig {
    
    @Bean  // 声明Bean
    public UserService userService() {
        return new UserServiceImpl(userDao());
    }
    
    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
}

2.Bean的声明

控制反转是将对象的控制权交给Spring的IOC容器,由IOC容器创建和管理对象,IOC容器创建的对象称为Bean对象。

要把某个对象交给IOC容器管理,需要在类上添加 @Component 注解。

@Component 及其衍生注解:

注解 说明 位置
@Component 声明bean的基础注解 不属于以下三类时,用此注解
@Controller @Component的衍生注解 标注在控制层类上
@Service @Component的衍生注解 标注在业务层类上
@Repository @Component的衍生注解 标注在数据访问层类上

声明Bean的时候,可以通过注解的value属性指定Bean的名字,如果没有指定,默认为 类名 首字母小写。

3.组件扫描

通过注解声明的Bean想要生效,还需要被组件扫描注解 @ComponentScan 扫描。@ComponentScan 注解主要用于启动类(@SpringBootApplication)、配置类(@Configuration)。

隐式使用

当使用 @SpringBootApplication 注解时,它已经包含了 @ComponentScan 注解,默认会扫描主类所在包及其子包:

java 复制代码
// 等价于:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class Application {
    // ...
}

显示指定扫描路径

如果组件不在默认包下,需要显示指定:

java 复制代码
@ComponentScan(basePackages = {
    "com.example.service",
    "com.example.repository",
    "com.example.controller"
})

4.依赖注入

依赖注入的常见方式,有以下三种:

4.1.构造器注入(推荐)

java 复制代码
@Service
public class UserService {
    private final UserDao userDao;
    
    // @Autowired 可省略(Spring 4.3+)
    public UserService(UserDao userDao) {
        this.userDao= userDao;
    }
}
  • 优点:能清晰地看到类的依赖关系、提高了代码的安全性。
  • 缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。

4.2.Setter注入

java 复制代码
@Service
public class UserService {
    private UserDao userDao;
    
    @Autowired
    public void setUserService(UserDao userDao) {
        this.userDao= userDao;
    }
}
  • 优点:保持了类的封装性,依赖关系更清晰。
  • 缺点:需要额外编写setter方法,增加了代码量。

4.3.属性注入(不推荐,测试时使用)

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}
  • 优点:代码简洁、方便快速开发。
  • 缺点:隐藏了类之间的依赖关系、可能会破坏类的封装性。

5.Bean的作用域

java 复制代码
@Component
@Scope("singleton")  // 默认,单例模式,整个容器中只有一个实例
public class SingletonBean { }

@Component
@Scope("prototype")  // 原型模式,每次获取都创建新实例
public class PrototypeBean { }

@Component
@Scope("request")    // 每个HTTP请求一个实例
public class RequestBean { }

@Component
@Scope("session")    // 每个HTTP Session一个实例
public class SessionBean { }
相关推荐
计算机毕设指导61 天前
基于微信小程序的考研资源共享系统【源码文末联系】
java·spring boot·后端·考研·微信小程序·小程序·maven
qq_165901691 天前
spring-cloud读取Nacos上的配置
java·spring cloud·springcloud
芒克芒克1 天前
深入浅出JVM的运行时数据区
java·开发语言·jvm·面试
毕设源码-赖学姐1 天前
【开题答辩全过程】以 影视资源分享论坛为例,包含答辩的问题和答案
java
沉默-_-1 天前
从小程序前端到Spring后端:新手上路必须理清的核心概念图
java·前端·后端·spring·微信小程序
xrkhy1 天前
多线程,高并发、物联网以及spring架构的面试题-->周
java·spring·架构
jgyzl1 天前
2025.12.21 学习web前必要知识点梳理
java·hash
a程序小傲1 天前
中国邮政Java面试被问:gRPC的HTTP/2流控制和消息分帧
java·开发语言·后端
forestsea1 天前
Springboot 4.0十字路口:虚拟线程时代,WebFlux与WebMVC的终极选择
java·后端·spring