springboot IOC

springboot IOC

IoC

Inversion of Control

Inversion 反转

依赖注入

DI (dependency injection )

dependency 依赖

injection 注入

Qualifier 预选赛

一文带你快速理解JavaWeb中分层解耦的思想及其实现,理解 IOC和 DI
https://zhuanlan.zhihu.com/p/15538831909

一文带你快速理解JavaWeb中分层解耦的思想及其实现,理解 IOC和 DI

上一次介绍了JavaWeb中请求响应相关的内容,这次来了解一下JavaWeb中分层解耦的思想及其实现,重点在于理解控制反转(IOC)和依赖注入(DI)。

一、三层架构

1、概述

1.1 controller(接收请求、响应数据)

控制层,接收前端发送的请求,对请求进行处理,并响应数据。

1.2 service(逻辑处理)

业务逻辑层,处理具体的业务逻辑。

1.3 dao(数据访问)

数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。


1.4 对比

以前的方式与三层架构方式对比。

二、分层解耦

1、 基本概念

1)内聚:软件中各个功能模块内部的功能联系。

2)耦合:衡量软件中各个层/模块之间的依赖、关联的程度。

软件设计原则:高内聚低耦合。

2、问题导入

探讨传统的MVC模式,三层架构代码书写存在的问题。我们先看一个代码示例,再对问题进行剖析。

c 复制代码
注:MVC模式是软件工程中常见的一种软件架构模式,该模式把软件系统(项目)分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

1)Dao层(dao包下接口和对应实现类)

1.1)BookDao接口(com.itweb.dao.BookDao)

c 复制代码
package com.itweb.dao;

public interface BookDao {
    void save(); // 抽象方法
}

1.2)BookDaoImpl实现类(com.itweb.dao.impl.BookDaoImpl)

package com.itweb.dao.impl;

import com.itweb.dao.BookDao;

public class BookDaoImpl implements BookDao { // BookDao接口的实现类

@Override

public void save() { // 重写接口中的抽象方法

System.out.println("book dao save...");

}

}

2)Service层(service包下接口和对应实现类)

2.1)BookService接口(com.itweb.service.BookService)

package com.itweb.service;

public interface BookService {

void save();

}

2.2)BookServiceImpl实现类

package com.itweb.service.impl;

import com.itweb.dao.BookDao;

import com.itweb.dao.impl.BookDaoImpl;

import com.itweb.service.BookService;

public class BookServiceImpl implements BookService {

// 在业务层(Service层)的接口实现类中调用数据层(Dao层)的接口实现类,高耦合的根源。

private BookDao bookDao=new BookDaoImpl(); // 面向接口编程

@Override

public void save() {

bookDao.save(); // 调用BookDaoImpl实现类中的方法

}

}

3)存在问题分析

3.1)在业务层(Service层)的接口实现类中调用数据层(Dao层)的接口实现类时,存在较高耦合性(即数据层实现类如果修改,则在业务层中调用的实现类也要修改,导致需要重新编译、测试、部署...),究其原因,是调用的实现类导致高耦合(凡是new出来的对象的调用都存在一定的耦合性)

3.2)解决办法

思路1:将new出来的实现类去掉,直接写接口,即将 private BookDao bookDao=new BookDaoImpl(); 改为 private BookDao bookDao; 但这样也是存在问题的,对象从哪里来呢?(IOC-->解耦)

思路2:在BookServiceImpl实现类中,业务层实现依赖 dao对象运行(因为在Service层中调用了dao对象的save方法),那么这种依赖关系该如何绑定呢?(依赖注入-->绑定)

综上,由此引出了两个重要话题:IOC(控制反转)和 DI(依赖注入)

3、IOC & DI概述

3.1 控制反转(IOC)

Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。

Spring对 IOC思想进行了实现:Spring提供了一个容器,称为IOC容器(即Spring架构中的 Core Container),用来充当IOC思想中的外部。IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为 Bean(Spring中对象都称为Bean)

3.2 依赖注入(DI)

Dependency Injection,简称DI。容器为应用程序提供运行时所依赖的资源(即在容器中建立bean与bean之间的依赖关系的整个过程)称为依赖注入。

3.3 Bean对象

IOC容器中创建、管理的对象,称为bean。

3.4 小结:(Spring实现充分解耦过程)

1.使用 IOC容器管理 bean对象 (IOC)

2.在IOC容器内将有依赖关系的 bean进行关系绑定 (DI)

3.最终效果

使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

4、IOC & DI入门程序

同样以我们问题导入那个案例作为入门程序,在原基础上做一些修改即可。具体为:

1、在对应的实现类上方添加 @Component注解实现控制反转

2、在删掉new对象的上方添加 @Autowired注解实现依赖注入

1)Dao层(dao包下接口和对应实现类)

1.1)BookDao接口(com.itweb.dao.BookDao)

package com.itweb.dao;

public interface BookDao {

void save(); // 抽象方法

}

1.2)BookDaoImpl实现类(com.itweb.dao.impl.BookDaoImpl)

package com.itweb.dao.impl;

import com.itweb.dao.BookDao;

import org.springframework.stereotype.Component;

@Component //将当前类交给IOC容器管理,成为IOC容器中的bean

public class BookDaoImpl implements BookDao { // BookDao接口的实现类

@Override

public void save() { // 重写接口中的抽象方法

System.out.println("book dao save...");

}

}

2)Service层(service包下接口和对应实现类)

2.1)BookService接口(com.itweb.service.BookService)

package com.itweb.service;

public interface BookService {

void save();

}

2.2)BookServiceImpl实现类

package com.itweb.service.impl;

import com.itweb.dao.BookDao;

import com.itweb.dao.impl.BookDaoImpl;

import com.itweb.service.BookService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

@Component //1.将当前类交给IOC容器管理,成为IOC容器中的bean

public class BookServiceImpl implements BookService {

// 在业务层(Service层)的接口实现类中调用数据层(Dao层)的接口实现类,高耦合的根源。

// private BookDao bookDao=new BookDaoImpl();

复制代码
@Autowired // 2.运行时,IOC容器会提供该类型的bean对象,并赋值给该变量(依赖注入)
private BookDao bookDao; // 删除业务层中使用new方式创建的dao对象
@Override
public void save() {
    System.out.println("book service save...");
    bookDao.save(); // 调用BookDaoImpl实现类中的方法
}

}

5、IOC & DI详解

5.1 Bean的声明

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

注:Controller(请求处理、响应数据),Service(逻辑处理),Dao(数据访问)

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

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

5.2 Bean组件扫描

前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。

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

@SpringBootApplication具有包扫描作用,默认扫描当前包及其子包

5.3 Bean注入

@Autowired注解,即自动装配,默认是按照类型进行,如果存在多个相同类型的bean,将会报出如下错误

通过以下几种方案来解决

1)@Primary

见名知意,该注解的作用即设置bean的优先级

@Primary

@Service

public class EmpServiceA implements EmpService {

}

2)@Qualifier

配合@Autowired一起使用

@RestController

public class EmpController {

@Autowired

@Qualifier("empServiceA")

private EmpService empService ;

3)@Resource

指定名称,按名称注入

@RestController

public class EmpController {

@Resource(name= "empServiceB")

private EmpService empService ;

4)小结

1.依赖注入的注解

@Autowired: 默认按照类型自动装配。

如果同类型的bean存在多个:

@Primary

@Autowired +@Qualifier("bean的名称")

@Resource(name="bean的名称")

2.@Resource 与@Autowired区别(重点--面试题)

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

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

相关推荐
JH30733 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
qq_12498707536 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_6 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_818732066 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
汤姆yu10 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶10 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip11 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
JavaGuide11 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
figo10tf12 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva12 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端