IOC & DI 专题

目录

三层架构

分层解偶

IOC & DI入门

Bean的声明

Bean组件扫描 

Bean的注入


三层架构

三层架构是一种常见的软件架构模式,它将应用程序划分为请求处理、响应数据层、业务逻辑层和数据访问层。每层之间通过接口进行通信,实现了高内聚、低耦合的设计原则。

  • 数据访问:负责业务数据的维护操作,包括增、删、改、查等操作
  • 逻辑处理:负责业务逻辑处理的代码
  • 请求处理、响应数据:负责,接收页面的请求,给页面响应数据

在传统的开发中,通常会将三层架构的代码都写着一个方法里

而为了让类、接口、方法的复杂度更低,可读性更强,扩展性更好,也更利用后期的维护,我们应该尽可能让一个类或一个方法,就只做一件事情,只管一块功能。

对上面代码进行拆分,可以得到下面三个类

虽然这样使代码的复用性,便于维护,利于拓展,还需要考虑一个软件的设计原则,那就是高内聚, 低耦合问题。也就是下面要讲的分层耦合。

分层解偶

分层解耦是软件开发中的重要思想,它通过将不同功能模块进行分离(上面代码已经完成),降低了系统各部分的依赖性,提高了系统的可维护性和可扩展性。在Spring框架中,IOC和DI是实现分层解耦的关键技术。

代码中可以看到EmpController依赖于EmpService,而EmpService又依赖于EmpDao,可以思考一下,当需要修改业务逻辑代码,将EmpService改为EmpServiceA,这是我们同样需要修改controller层的代码为:

//private EmpService empService = new EmpService改为
private EmpServiceA empService = new EmpServiceA

看到这里应该就明白了耦合的关系,也就是底层代码更改,上层代码也要跟着修改,而上面代码的关系就如下图:

而分层解耦就是要把耦合关系解除这个问题

用上面代码private EmpServiceA empService = new EmpServiceA来举例

我们把他分为EmpServiceA empServicenew EmpServiceA右两个部分去理解

首先如何让EmpServiceA empService这部分进行解藕?

设想一下我们常用的支付功能,需要用不同的平台如微信,支付宝等去支付,那我们是不是就需要微信和支付宝两个实现类,不难看出多态就能解决这个问题

建立一个UserService接口,把业务层代码分别实现接口,这样就解决了EmpServiceA empService的解藕,(与下面截图命名有些许出入,但原理是一样的)

同时思考下,如果我们自己不手动的去new对象,是不是new EmpServiceA这部分的耦合也就解决掉了,这时候就有个疑问,controller层的userService没有初始化new对象不就空指针了吗,这个问题不用我们考虑,下面要讲的Spring框架的IOC容器会帮我们解决这个问题

IOC & DI入门

首先了解什么是IOC,什么是DI

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

Dependency Injection,简称DI:容器为应用程序提供运行时所依赖的资源,称之为依赖注入

把需要创建的对象UserServcieB交给IOC容器管理,这个过程叫做控制反转

IOC容器向userService变量提供依赖的对象,这个过程叫做依赖注入

这是又有个疑问,如果A和B都在IOC容器里,怎么保证userService可以取到我们想要的对象,这个问题先放一放,看完下面Bean的声明和注入就知道了

注:在IOC容器中的对象统一称为Bean

理解了IOC与DI的思想,下面来实现使用IOC & DI完成业务解耦

  • 使用Spring提供的注解:@Component ,就可以实现类交给IOC容器管理

  • 使用Spring提供的注解:@Autowired ,就可以实现程序运行时IOC容器自动注入需要的依赖对象

通过这个例子应该对IOC和DI都有一定了解了,下面讨论一下两者的细节

Bean的声明

要把某个对象交给IOC容器管理,需要把对应的类加上如下注解之一, 衍生注解声明可以更好的区分bean是属于那一层的

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

 注:

  • 声明bean的时候,可一通过value属性指定bean的名字,如果没有指定,默认类名首字母小写
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller。

Bean组件扫描 

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

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

底层源码中可以看到@ComponentScan注解包含在@SpringBootApplication中

 试着把dao包移出来,与@SpringBootApplication所在的包平级,会报错找不到bean

想要扫描到dao包,可以手动添加@ComponentScan注解指定要扫描的包 ,一旦使用注解,默认扫描就会被覆盖,需要把所有要扫描的包都写上(不推荐)

推荐按照springboot项目的规范,将所写的代码全部放在引导类所在包及其子包下,使spring启动时自动的扫描到这些bean对象,这样可以少很多不必要的配置

Bean的注入

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

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

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

运行之后也给出了解决档案,下面通过这几种方案来解决:

@Primary

@Qualifier

@Resouce 

使用@Primary注解:Primary中文为优先的,从翻译来看不能理解,当存在多个相同类型的Bean注入时,加上@Primary注解优先使用该bean注入

使用@Qualifier注解:指定当前要注入的bean对象。

在@Qualifier的value属性中,指定注入的bean的名称。如下指定注入名字为empServiceA的bean对象

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

使用@Resource注解:不需要@Autowired,直接按bean的名称进行注入。通过name属性指定要注入的bean的名称。

如下指定注入名字为empServiceB的bean对象

 @Autowird 与 @Resource的区别

  • @Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
  • @Autowired 默认是按照类型注入,而@Resource是按照名称注入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

癞皮狗不赖皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值