一、前言

本文通过分析若依(RuoYi)开源项目,深入学习 Spring IOC、DI 和 Spring MVC 注解的实际应用。 RuoYi 是一个基于 Spring Boot 的权限管理系统,代码规范,非常适合学习 Spring 框架的使用。

本文将从以下几个方面进行分析: 1. Spring 环境启动流程 2. Spring IOC 和 DI 注解的使用 3. Spring MVC 注解的使用 4. 拓展:接口多实现类的自定义注入

二、Spring 环境启动

2.1 启动类分析

2.1.1注解说明:

  1. @SpringBootApplication
    • 这是 Spring Boot 的核心注解,是一个组合注解
    • 包含三个注解:
      • @SpringBootConfiguration:标记为配置类
      • @EnableAutoConfiguration:启用自动配置
      • @ComponentScan:自动扫描组件
  2. exclude = { DataSourceAutoConfiguration.class }
    • 排除数据源自动配置
    • 原因:RuoYi 使用了 Druid 多数据源,需要自定义配置
  3. SpringApplication.run()
    • 启动 Spring 容器
    • 参数1:主配置类
    • 参数2:命令行参数

2.2启动流程:

启动 main 方法
    ↓
加载 @SpringBootApplication 注解
    ↓
扫描所有带 @Component、@Service、@Repository、@Controller 的类
    ↓
创建 Bean 并放入 IOC 容器
    ↓
处理 @Autowired、@Resource 等依赖注入
    ↓
启动内置 Tomcat 服务器
    ↓
应用启动成功

三、Spring IOC 注解使用(创建对象)

3.1 使用 @Configuration + @Bean 创建对象

3.1.1注解说明:

  1. @Configuration
    • 标记这是一个配置类,相当于 XML 配置文件
    • Spring 会在启动时加载这个类
    • 类中的 @Bean 方法会被执行
  2. @Bean(name = "captchaProducer")
    • 将方法返回的对象注册为 Spring Bean
    • Bean 的名称为 "captchaProducer"
    • 这个 Bean 可以在其他地方通过 @Resource 或 @Autowired 注入
  3. @Bean(name = "captchaProducerMath")
    • 注册第二个验证码生产者 Bean
    • Bean 名称为 "captchaProducerMath"
    • 用于生成数学运算验证码

3.1.2 为什么要创建两个 Bean?

①captchaProducer:生成普通字符验证码(如:abcd)
②captchaProducerMath:生成数学运算验证码(如:1+2=?)
③系统可以根据配置选择使用哪种验证码

3.1.3 IOC 容器中的 Bean:

Spring IOC 容器
├── captchaProducer (DefaultKaptcha 对象)
└── captchaProducerMath (DefaultKaptcha 对象)

3.2 使用 @Component 创建对象


 

3.2.1 注解说明:

  1. @Component
    • 通用组件注解,将 RedisCache 类注册为 Spring Bean
    • Spring 启动时会自动创建这个类的实例
    • Bean 名称默认为类名首字母小写:redisCache
  2. @Autowired
    • 自动注入 RedisTemplate Bean
    • Spring 会从 IOC 容器中查找 RedisTemplate 类型的 Bean 并注入

3.2.2 类的作用:

  ①封装 Redis 操作
  ②提供缓存的增删改查方法
  ③简化 Redis 的使用

3.3 使用 @Service 创建对象

3.3.1 注解说明:

  1. @Service
    • 业务逻辑层注解,将 SysConfigServiceImpl 注册为 Spring Bean
    • 本质上也是 @Component,但语义更明确
    • 表示这是一个业务逻辑处理类
  2. @Autowired
    • 注入 SysConfigMapper(数据访问层)
    • 注入 RedisCache(缓存工具类)

3.3.2 类的作用:

  ①处理系统配置相关的业务逻辑
  ②先从 Redis 缓存中查询配置
   ③缓存不存在时从数据库查询并缓存

3.3.3 分层架构:

Controller 层(接收请求)
    ↓
Service 层(业务逻辑)← SysConfigServiceImpl
    ↓
Mapper 层(数据访问)

四、Spring DI 注解使用(依赖注入)

4.1 使用 @Resource 按名称注入

4.1.1注解说明:

  1. @Resource(name = "captchaProducer")
    • 按名称注入 Bean
    • 从 IOC 容器中查找名称为 "captchaProducer" 的 Bean
    • 这个 Bean 是在 CaptchaConfig 中通过 @Bean 创建的
  2. @Resource(name = "captchaProducerMath")
    • 按名称注入 Bean
    • 从 IOC 容器中查找名称为 "captchaProducerMath" 的 Bean
    • 这个 Bean 是在 CaptchaConfig 中通过 @Bean 创建的
  3. @Autowired
    • 按类型自动注入
    • 注入 RedisCache 和 ISysConfigService

4.2 @Resource 和 @Autowired 的区别:

注解 注入方式 来源 使用场景
@Resource 按名称注入 JDK标准注解 有多个相同类型的Bean时
@Autowired 按类型注入 Spring注解 只有一个该类型的Bean时

4.3依赖注入流程:

Spring 容器启动
    ↓
创建 CaptchaController 对象
    ↓
发现 @Resource(name = "captchaProducer")
    ↓
从 IOC 容器中查找名为 "captchaProducer" 的 Bean
    ↓
将 Bean 注入到 captchaProducer 字段
    ↓
发现 @Autowired
    ↓
从 IOC 容器中查找 RedisCache 类型的 Bean
    ↓
将 Bean 注入到 redisCache 字段
    ↓
依赖注入完成,对象可以使用

五、Spring MVC 注解使用

PPT 中讲解了 @RestController@GetMapping@RequestBody 等基础的路由和请求体注解。在 RuoYi 项目的实际开发中,为了设计更加优雅的 RESTful 风格 API,经常会用到 PPT 中未列出的拓展注解——@PathVariable

5.1 使用 @PathVariable 动态绑定路径参数

5.1.1 注解说明:

@PathVariable

作用: 将 HTTP 请求 URL 路径中的模板变量(如上方的 /{userId}),动态解析并绑定到处理函数的参数上。

属性 value: 指定要绑定的 URL 变量名称("userId")。

属性 required: 设为 false 表示该参数不是必传项(因为映射路径有 //{userId} 两种情况)。

5.1.2 完整请求处理流程(包含 Spring 启动):

Spring Application 启动
  ↓
内嵌 Tomcat 服务器启动,DispatcherServlet 准备就绪
  ↓
Spring MVC 扫描带 @RestController 的类,将 SysUserController 注册到容器
  ↓
解析 @GetMapping,将路由 "/system/user/{userId}" 与 getInfo 方法建立映射关系
  ↓
前端发起请求:GET http://localhost/system/user/1001
  ↓
DispatcherServlet 拦截请求并匹配路由
  ↓
解析路径参数:@PathVariable 自动提取 URL 中的 "1001",转换为 Long 类型
  ↓
将 1001 注入到形参 userId 中,进入函数执行业务逻辑
  ↓
返回 JSON 结果给前端

六、拓展:接口多实现类的自定义注入

6.1 问题场景与操作步骤

当一个接口(例如 ISysUserService)存在多个实现类时,如果在 Controller 中直接使用 @Autowired(默认按类型注入),Spring 容器会因为找到多个相同类型的 Bean 而陷入迷茫,从而抛出异常。

要解决这个问题,我们需要结合名称注解进行精确制导:

此处左边是我自己写的一个自定义 Service 实现类(带 @Service("myCustomUserService")),右边是 Controller 里使用 @Resource(name = "myCustomUserService") 注入的代码。

步骤 1:定义并注册 Bean(为自定义实现类起个特定名字)

1.在 IDEA 的左侧项目目录中,找到这个路径:ruoyi-system -> src -> main -> java -> com.ruoyi.system.service.impl

2.在这个 impl 文件夹上右键,选择 New -> Java Class,给它起名叫MyCustomUserServiceImpl,你们也可以选择自己起个名字。

3.定义并注册bean,如下面代码所示(你们通过继承原有的类来偷懒,这样就不用重写那几十个接口方法了):

// 使用 @Service 注解,并显式指定 Bean 的名称为 "myCustomUserService"
@Service("myCustomUserService")
public class MyCustomUserServiceImpl implements ISysUserService {
    // ... 自定义的重写逻辑
}

步骤 2:注入自己实现的 Bean(按名称注入)

1.找到路径:ruoyi-admin -> src -> main -> java -> com.ruoyi.web.controller.system -> SysUserController

2.打开 SysUserController,在代码的开头部分,你会看到原来写的是 @Autowired

放弃单纯的类型匹配,改用按名称匹配,确保注入的是我们自己的实现类。

3.把原来的注入代码稍作修改,可以参考下面代码。

@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController {

    // 结合具体名称进行精确注入
    @Resource(name = "myCustomUserService")
    private ISysUserService userService;
    
    // 或者使用 @Autowired 配合 @Qualifier
    // @Autowired
    // @Qualifier("myCustomUserService")
    // private ISysUserService userService;
}

6.2 现实意义分析

很多成熟的开源框架(如 RuoYi)已经提供了完善的基础接口实现。但在实际的 CSMD (Controller, Service, Model/Mapper, DAO/Data) 分层架构开发中,我们往往需要针对特定的定制化需求重写核心的 Service 逻辑。

如果直接修改框架原本的源码,会导致后续框架升级困难。而利用 Spring 这种“多实现类 + 指定 Bean 名称注入”的机制,我们可以在完全不触碰框架原有 Controller 和原生 Service 源码的前提下,仅通过新增一个带有特定 @Service("自定义名称") 的实现类,并在业务调用处修改注入名称,就能实现底层业务逻辑的无缝替换。这极大地提高了代码的灵活性,完美契合了面向对象设计中的“开闭原则”(对扩展开放,对修改关闭)。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐