SpringBoot之IOC&DI的详细解析

发布时间:2023年12月20日
3.3.2 IOC详解

通过IOC和DI的入门程序呢,我们已经基本了解了IOC和DI的基础操作。接下来呢,我们学习下IOC控制反转和DI依赖注入的细节。

3.3.2.1 bean的声明

前面我们提到IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。

在之前的入门案例中,要把某个对象交给IOC容器管理,需要在类上添加一个注解:@Component

而Spring框架为了更好的标识web应用程序开发当中,bean对象到底归属于哪一层,又提供了@Component的衍生注解:

  • @Controller (标注在控制层类上)

  • @Service (标注在业务层类上)

  • @Repository (标注在数据访问层类上)

修改入门案例代码:

  • Controller层:

@RestController ?//@RestController = @Controller + @ResponseBody
public class EmpController {
?
 ? ?@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
 ? ?private EmpService empService ;
?
 ? ?@RequestMapping("/listEmp")
 ? ?public Result list(){
 ? ? ? ?//1. 调用service, 获取数据
 ? ? ? ?List<Emp> empList = empService.listEmp();
?
 ? ? ? ?//3. 响应数据
 ? ? ? ?return Result.success(empList);
 ?  }
}
  • Service层:

@Service
public class EmpServiceA implements EmpService {
?
 ? ?@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
 ? ?private EmpDao empDao ;
?
 ? ?@Override
 ? ?public List<Emp> listEmp() {
 ? ? ? ?//1. 调用dao, 获取数据
 ? ? ? ?List<Emp> empList = empDao.listEmp();
?
 ? ? ? ?//2. 对数据进行转换处理 - gender, job
 ? ? ? ?empList.stream().forEach(emp -> {
 ? ? ? ? ? ?//处理 gender 1: 男, 2: 女
 ? ? ? ? ? ?String gender = emp.getGender();
 ? ? ? ? ? ?if("1".equals(gender)){
 ? ? ? ? ? ? ? ?emp.setGender("男");
 ? ? ? ? ?  }else if("2".equals(gender)){
 ? ? ? ? ? ? ? ?emp.setGender("女");
 ? ? ? ? ?  }
?
 ? ? ? ? ? ?//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
 ? ? ? ? ? ?String job = emp.getJob();
 ? ? ? ? ? ?if("1".equals(job)){
 ? ? ? ? ? ? ? ?emp.setJob("讲师");
 ? ? ? ? ?  }else if("2".equals(job)){
 ? ? ? ? ? ? ? ?emp.setJob("班主任");
 ? ? ? ? ?  }else if("3".equals(job)){
 ? ? ? ? ? ? ? ?emp.setJob("就业指导");
 ? ? ? ? ?  }
 ? ? ?  });
 ? ? ? ?return empList;
 ?  }
}

Dao层:

@Repository
public class EmpDaoA implements EmpDao {
 ? ?@Override
 ? ?public List<Emp> listEmp() {
 ? ? ? ?//1. 加载并解析emp.xml
 ? ? ? ?String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
 ? ? ? ?System.out.println(file);
 ? ? ? ?List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
 ? ? ? ?return empList;
 ?  }
}

要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:

注解说明位置
@Controller@Component的衍生注解标注在控制器类上
@Service@Component的衍生注解标注在业务类上
@Repository@Component的衍生注解标注在数据访问类上(由于与mybatis整合,用的少)
@Component声明bean的基础注解不属于以上三类时,用此注解

查看源码:

在IOC容器中,每一个Bean都有一个属于自己的名字,可以通过注解的value属性指定bean的名字。如果没有指定,默认为类名首字母小写。

注意事项:

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

  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

3.3.2.2 组件扫描

问题:使用前面学习的四个注解声明的bean,一定会生效吗?

答案:不一定。(原因:bean想要生效,还需要被组件扫描)

下面我们通过修改项目工程的目录结构,来测试bean对象是否生效:

运行程序后,报错:

为什么没有找到bean对象呢?

  • 使用四大注解声明的bean,要想生效,还需要被组件扫描注解@ComponentScan扫描

@ComponentScan注解虽然没有显式配置,但是实际上已经包含在了引导类声明注解 @SpringBootApplication 中,默认扫描的范围是SpringBoot启动类所在包及其子包

  • 解决方案:手动添加@ComponentScan注解,指定要扫描的包 (仅做了解,不推荐)

推荐做法(如下图):

  • 将我们定义的controller,service,dao这些包呢,都放在引导类所在包com.itheima的子包下,这样我们定义的bean就会被自动的扫描到

3.3.3 DI详解

上一小节我们讲解了控制反转IOC的细节,接下来呢,我们学习依赖注解DI的细节。

依赖注入,是指IOC容器要为应用程序去提供运行时所依赖的资源,而资源指的就是对象。

在入门程序案例中,我们使用了@Autowired这个注解,完成了依赖注入的操作,而这个Autowired翻译过来叫:自动装配。

@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)

入门程序举例:在EmpController运行的时候,就要到IOC容器当中去查找EmpService这个类型的对象,而我们的IOC容器中刚好有一个EmpService这个类型的对象,所以就找到了这个类型的对象完成注入操作。

那如果在IOC容器中,存在多个相同类型的bean对象,会出现什么情况呢?

  • 程序运行会报错

如何解决上述问题呢?Spring提供了以下几种解决方案:

  • @Primary

  • @Qualifier

  • @Resource

使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。

使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。

  • @Qualifier注解不能单独使用,必须配合@Autowired使用

使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称。

面试题 : @Autowird 与 @Resource的区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解

  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入

文章来源:https://blog.csdn.net/qq_69748833/article/details/135117530
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。