Spring IoC&DI

目录

1.Spring是什么?

2.详解Ioc

2.1Bean的存储

[2.2 Bean Name默认命名规则](#2.2 Bean Name默认命名规则)

[2.3 扫描路径](#2.3 扫描路径)

2.4@Autowired和@Resource区别

[2.5 @Autowired查找Bean顺序](#2.5 @Autowired查找Bean顺序)

3.详解DI

Spring三种依赖注入方式优缺点对比


1.Spring是什么?

Spring 是一个开源的 Java 开发框架 ,核心目标是简化企业级应用开发。它提供了模块化工具(如 Spring MVC、Spring Security、Spring Data 等),让开发者更专注于业务逻辑,而非重复的底层代码。也就是包含了众多方法的IoC容器,

容器是什么?

在 Spring 中,容器是一个 装对象的"盒子", 它负责创建、配置、组装你编写的 Java 对象(称为 Bean),并管理它们的生命周期。

Ioc(控制反转)是什么?

谁使用谁控制=>Spring来控制

是 Spring 的核心思想。传统代码中,对象自己控制依赖的创建(如 new Service());而 IoC 将控制权"反转"给容器------你只需声明依赖关系,容器自动注入所需对象。

例如:

复制代码
// 传统方式:程序员自己创建依赖
UserService service = new UserService();

// IoC 方式:容器自动注入依赖
@Autowired
private UserService service;

简述Ioc和di

控制反转(IoC)的核心思想是将对象的创建和管理权从传统的"谁使用谁控制"模式转变为由框架(如Spring)统一管理。这种方式有效降低了组件间的耦合度,使系统更易于维护和扩展。

在IoC模式下,对象的生命周期完全由Spring容器管理,开发者无需手动实例化对象。依赖注入(DI)是IoC的一种实现方式,通过DI,Spring容器在运行时自动将依赖的对象注入到目标组件中,开发者只需声明依赖关系即可获得所需实例。

通过在类上面注释**@Component**:告诉Spring将该对象的控制权转给Spring

在类中注明依赖之后注释**@Autowired**:表明从Spring容器中拿出该对象并赋值给注明的依赖

2.详解Ioc

2.1Bean的存储

Spring为了更好地完善web服务提供许多注解能够完成对象的存储,代替**@Component**

类注解:@Controller,@Service,@Repository,@Component,@Configuration

方法注解:@Bean

类注解:

@Controller(控制器存储)

复制代码
@Controller
public class UserController {
    public String sayHello(){
        return "Hello World!";
    }
}
复制代码
public static void main(String[] args) {
    //应用上下文
    ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
    //通过getBean方法观察是否能拿到UserController对象
//拿到说明通过@Controller,对象成功创建并且存储到Spring容器当中
    UserController bean = context.getBean(UserController.class);
    System.out.println(bean.sayHello());
}

其他注解均可用同样的方法验证存储功能,如@Service:

复制代码
@Service
public class UserService {
    public String doService(){
        return "doService";
    }
}
复制代码
@SpringBootApplication
public class SpringIocDemoApplication {

    public static void main(String[] args) {
       //应用上下文
       ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);

       UserService bean = context.getBean(UserService.class);
       System.out.println(bean);

    }

}

因此后续类注解同上验证不做过多重复解释,既然起到效果相似,为什么还要有这么多?

原因是为了语义更加清晰,提高可读性,在对应的三层架构中使用对应的注解能更好的理解语义

//不好的实践 :因为其余注解都是@Component的衍生注解 ,因此都使用@Component
@Component

public class UserController { } // 这是控制器吗?服务吗?看不出来

@Component

public class UserService { } // 这是服务层吗?工具类吗?无法分辨

@Component

public class UserDao { } // 这是数据访问层吗?不清楚

// 好的实践:语义明确
@Controller

public class UserController { } // 明确是控制器,处理HTTP请求

@Service

public class UserService { } // 明确是服务层,处理业务逻辑

@Repository

public class UserDao { } // 明确是数据访问层

方法注解:开发人员自己创建对象交给Spring去管理,用于解决同一个类需要多个对象的问题/创建第三方对象

注意**:** 需配合类注解使用

复制代码
UserInfo类

@AllArgsConstructor//有参构造方法
@NoArgsConstructor//无参构造方法
@Data
public class UserInfo {
    private String name;
    private int age;
}
复制代码
BeanConfig类

@Configuration
public class BeanConfig {
    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",12);//自主创建对象
    }
}
复制代码
@SpringBootApplication
public class SpringIocDemoApplication {

    public static void main(String[] args) {
       ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);

       UserInfo bean1 = context.getBean(UserInfo.class);
       System.out.println(bean1);

    }

}

可以看到能够通过**@Bean** 使Spring 得到对UserInfo对象的控制权

接下来解决多个对象创建的问题

复制代码
@Configuration
public class BeanConfig {
//创建两个UserInfo对象,方法名区分开
    @Bean
    public UserInfo userInfo(){
        return new UserInfo("zhangsan",12);
    }
    @Bean
    public UserInfo userInfo2(){
        return new UserInfo("lisi",16);
    }
}
复制代码
@SpringBootApplication
public class SpringIocDemoApplication {

    public static void main(String[] args) {
       ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class, args);
       //只靠类型无法区分对象,因此传入对象名作为参数
       UserInfo bean1 = context.getBean("userInfo",UserInfo.class);
       System.out.println(bean1);
       UserInfo bean2 = context.getBean("userInfo2",UserInfo.class);
       System.out.println(bean2);
    }

}

2.2 Bean Name默认命名规则

(1)类注解

  • 类名前两位为大写,如USerinfo=>bean name 为原类名
  • 其他情况=>bean name 为类名的小驼峰形式

(2)方法注解

  • bean name 为方法名

2.3 扫描路径

默认情况下,Spring Boot 只扫描启动类所在包及其子包

但是可以通过**@ComponentScan(basePackages="")**来指定要扫描的路径

2.4@Autowired和@Resource区别

@Autowired是Spring 提供的注解,根据类型进行注入

@Resource是JDK 提供的注解,根据名称注入

2.5 @Autowired查找Bean顺序

  1. 按类型查找 Bean

    • 根据依赖的类型(Class/Interface)在 Spring 容器中查找匹配的 Bean。
  2. 判断是否找到

    • 如果未找到​ →报错

    • 如果找到​ → 进入下一步判断。

  3. 是否配置了 @Qualifier参数?

    • 如果已配置 @Qualifier ​ → 按 @Qualifier指定的名称进一步筛选 Bean。

      • 如果找到唯一匹配 → 装配成功 ✅。

      • 如果未找到或仍匹配多个 → 抛异常 ❌。

    • 如果**未配置 @Qualifier**​ → 进入默认策略(按字段名匹配)。

  4. 字段名匹配

    • 匹配成功→装配成功

    • 未匹配→说明未指定名称,进入下一判断

  5. 是否只有一个Bean

    • 如果只有一个bean → 直接装配

3.详解DI

依赖注入是一个过程 ,是ioc容器创建Bean的过程中提供所依赖的资源 ,这个资源就是对象

Spring提供了三种方式:

(1)属性注入@Autowired

@Component
public class UserService {
// 方式1:直接注入到属性
@Autowired
private UserRepository userRepository;
}

(2)构造方法注入

@Service

public class UserService {

// 使用final,确保依赖不可变

private final UserRepository userRepository;

// 构造方法注入

public UserService(UserRepository userRepository) {

this.userRepository = userRepository;

}

}

注意:

  • 只有一个构造方法时默认执行这一个
  • 多个构造方法默认执行无参构造,若没有无参构造则报错
  • 可通过@Autowired注解指定执行的构造方法

(3)Setter注入

@Service

public class UserService {

private UserService userService;

// Setter注入

@Autowired

public voidsetUserService (UserService userService) {

this.userService = userService;

}

}

Spring三种依赖注入方式优缺点对比

对比维度 构造方法注入 Setter注入 属性注入
代码简洁性 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
可读性 优秀(依赖一目了然) 良好 (依赖关系隐藏)
不可变性 支持final(线程安全) 不支持final 不支持final
单元测试 最容易(直接传参) 容易 困难(需要反射)
依赖完整性 保证(对象创建即完整) 不保证(可能部分注入) 不保证
循环依赖检测 启动时报错 Spring可处理 Spring可处理
可选依赖支持 ⭐ 有限(需Optional包装) 优秀(required=false) 支持
框架耦合度 ⭐ 低 ⭐ 低 (强依赖Spring)
代码重构 ⭐⭐⭐ ⭐⭐⭐⭐ 最容易
复制代码
复制代码
复制代码
相关推荐
液态不合群3 小时前
[特殊字符] MySQL 覆盖索引详解
数据库·mysql
计算机毕设VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue蛋糕店管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
瀚高PG实验室4 小时前
PostgreSQL到HighgoDB数据迁移
数据库·postgresql·瀚高数据库
打码人的日常分享5 小时前
智能制造数字化工厂解决方案
数据库·安全·web安全·云计算·制造
三水不滴5 小时前
Redis 过期删除与内存淘汰机制
数据库·经验分享·redis·笔记·后端·缓存
-孤存-6 小时前
MyBatis数据库配置与SQL操作全解析
数据库·mybatis
2301_822366356 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
wangqiaowq8 小时前
MSSQLSERVER 和 SQLEXPRESS 是 SQL Server 中两种不同类型的实例名称
sql
万邦科技Lafite8 小时前
一键获取京东商品评论信息,item_reviewAPI接口指南
java·服务器·数据库·开放api·淘宝开放平台·京东开放平台