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 { }
相关推荐
怀旧诚子1 小时前
timeshift之Fedora43设置,已在VM虚拟机验证,待真机验证。
java·服务器·数据库
1104.北光c°1 小时前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
云原生指北4 小时前
GitHub Copilot SDK 入门:五分钟构建你的第一个 AI Agent
java
Leinwin8 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
薛定谔的悦8 小时前
MQTT通信协议业务层实现的完整开发流程
java·后端·mqtt·struts
enjoy嚣士9 小时前
springboot之Exel工具类
java·spring boot·后端·easyexcel·excel工具类
罗超驿9 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
盐水冰10 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头10 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun31415910 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm