Spring IoC & DI
前置知识: 什么是容器?
容器: 装东西的装置.Spring就是包含了众多工具方法的IoC容器
1.1 Spring IoC & DI 概念
我们先来看这么一个例子:
我们现在的需求是造车:
先设计轮子,根据轮子大小设计底盘,根据底盘设计车身,根据车身设计整个车.
我们给一个指定的大小就能生成车.
但是此时有个问题,我增加需求: 我需要修改车轮的颜色,此时就要一路沿着车轮,底盘,车身一路改过去.耦合性就很大
我们换一种思路,先设计车大致样子,再根据车的样子设计车声,根据车身来设计底盘,最后根据底盘设计轮子.
直接把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.
对比一下俩种方式:
此时我们修改需求,就直接在main里面修改即可,这就完成了代码的解耦
此时main就是一个,第三方的资源管理.这个main方法就对应着我们的Spring容器,我们的Spring,就已经创建了这些对象,我们直接拿来用就好了
IoC (Inversion of Control) 控制反转,也就是控制权反转,指的是对对象的控制权反转.之前我们就使用过IoC: @RestController,表示申明这个对象,把这个对象交给Spring进行管理.也就是把创建对象的控制权交给Spring来进行管理
DI (Dependency Injection) 依赖注入,在运行时间为程序提供运行时所依赖的资源.
总的来说就是: 在程序运行的时候,动态的把依赖进行赋值,然后注入到这个对象里面去.
看个例子:
这里面的BookService对象是由BookController来进行创建的,但是此时我不想自己创建,我想直接交给Spring来进行创建.
我们通过@Component注解,把BookService这个对象交给Spring来进行创建
然后我们使用DI,从Spring里面把这个对象取出来.此时我们需要使用@Autowired注解,把BookService这个对象从Spring里面取出来.
对比: 此时我们发现我们并没有new一个对象,而是直接使用存在Spring里面的对象
1.2 IoC的好处(面试八股文)
资源不用使用资源的双方管理,而是由不使用资源的第三方进行管理,这样就有下面几个好处,第一: 资源集中管理,实现资源的可配置和易管理: IoC容器会帮我们管理一些资源(对象),为你需要使用时,只需要从IoC容器中取就行. 第二: 降低了资源双方的依赖程度,也就是耦合度,简单来讲就是降低了耦合度
1.3 IoC和DI之间的关系
IoC是控制反转,也就是有个第三方的容器(比如Spring)帮我创建好了对象.DI就是从这个容器里面拿到这个对象,然后进行赋值.
1.4 什么样的对象适合交给Spring进行管理?
无状态的对象,也就是不管谁来访问,结果都是一样的.
3.1 bean的介绍
什么是bean?
简而言之: bean就是归spring管理的对象
IoC&DI和bean的关系
Ioc 控制反转: 把创建对象的控制权交给了Spring进行管理,使用@Controller,@Component...这个就是bean的存储
DI 依赖注入: 从Spring里面把创建的对象拿出来并且进行赋值,使用@Autowired 这个就是bean的获取
前置知识:
ApplicationContext :里面装的是Spring运行环境所有的信息
ApplicationContext 和BeanFeactory关系以及区别(八股文)
1. 关系: 他俩是父子关系ApplicationContext是父,BeanFeactory是子,BeanFeactory的功能,ApplicationContext都有,除此之外ApplicationContext还具备 资源 环境管理等功能.
2. 区别: Beanfactory是懒加载(用到的时候才会创建这个Bean),ApplicationContext是提前加载.ApplicationConetxt性能会比较好,但是因为是提前把所有的Bean都加载出来了,那么就会浪费空间.但是现在基本上内存不值钱了,因此大多还是用ApplicationContext.
3.1.2 bean的存储
IoC告诉Spring,我要存储那个bean,如何告诉?俩种方式:1.类注解,2.方法注解
类注解
类注解有5种,分别是@Controller(表现层)@Componet(组件相关)@Service(业务逻辑层)@Configuration(配置相关)@Repository(数据层)
1. @Controller
直接在类上面加入@Controller注解,把这个对象放到Spring里面
然后我们取出来
这时需要启动类,这个是个导包问题
此时我们获得bean有很多方式,我们只介绍三种
1.通过bean的名称获得bean
我们先认识一下什么是bean的名称
类型相当于学生的名称(可能有重复的,一个类型可能往Spring里面放置了多个对象),Bean的名称是在Spring容器种唯一的,类似于学生的学号或者身份证号.总而言之,bean的名称是唯一的.
我们运行一下启动类,成功把放进去的Spring对象取出来了
2.通过bean的类型获得bean
这里报错的原因就是,我们根据类型获取bean,此时里面应该是小驼峰
改成小驼峰之后成功了
但是有一种特殊情况,也就是开头俩个字母是连着大写的类.当我们的类名字超过连续俩个字母是大写的,那么我类的名称就是我们类原始的名称,而不是小驼峰的形式
修改后,运行成功
此时我们需要了解一下bean的命名规则
bean的命名规则
我们看下官⽅⽂档的说明: Bean Overview :: Spring Framework
总结:
默认情况下:首字母小写的驼峰表示.
特殊情况:如果类名称前俩位都是大写,和类名的名称是一样的
3. 通过类型和bean的名称一起获得bean
注意: 不管什么怎么取,都是同一个对象
2. @Component
我们使用@Component把这个对象放到Spring里面去
此时我们只使用一种方式来拿出来
3. @Service
我们在类上面加上@Service这个注解,把这个对象放在Spring里面
取出来
4. @Repository
我们在这个类上面加上@Respository这个注解,把这个对象放到Spring里面去
取出来
5. @Configuration
我们把@Configuration放到类的上面,把这个对象放到Spring里面
取出来
五大类注解之间的关系:
基本上可以混用,但是不推荐.硬要混用,记住只要有路由映射就都使用Controller.其他条件都是能混用
方法注解
1. 使⽤外部包⾥的类, 没办法添加类注解
2. ⼀个类, 需要多个对象, ⽐如多个数据源这种场景, 我们就需要使⽤⽅法注解@Bean
@Bean也是需要配合五大注解来使用的
注意:这个记得删除,spring3升级导致的lombok没生效(每次删完记得刷新一下)
使用@Bean注解,把这个方法交给Spring进行管理(此时我们通过类名来获取)
但是此时我们把多个同类型的Bean放进去,因为时单例模式,只能有一个
此时我们通过方法名称来获取
@Bean的命名方式
直接根据方法名称来命名(不管大小写)
bean名称总结:
1.五大注解
类名: 首字母小写
如果类名称,前俩位为大写,bean的名称为类名本身
2.@Bean
bean名称: 方法名
如何告诉Spring去扫描哪些程序?
这个就和启动类有关系了.我们看一个例子
我们修改启动类的目录结构
再次运行,发现报错,这说明我们找不到我们的路径,启动类默认扫描路径是,他本层及下面的子目录.因为 启动类的源码包含了扫描路径的功能.
我们可以通过@ComponentScan手动设定扫描路径.此时就可以了,这里注意,我们{}里面是可以放置多个位置的,比如:
@ComponentScan(basePackages = {"org.xiaobai","com.fasterxml.jackson.core.async"})
3.1.3 bean的取出(DI注入的三种方式)
DI我们使用的是@Autowired这个注解
1 属性注入
我们直接把@Autowired放在我们要使用的没有new的类的前面
2 构造方法注入
单个构造方法的情况
多个构造方法的情况,发现报错了.因为Spring在创建对象的时候就是用的构造函数,此时我们有俩个构造函数,因此它只用无参的,那么我们创建出来的就是个null.默认我们用的是无参的.因此userService就是个空的对象.
如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法,那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法。
构造函数注入总结:
1. 如果只有一个构造函数,不需要加入AutoWired
2. 如果有多个构造函数,需要指定默认的构造函数(Autowired指定,如果没有指定就默认使用无参的构造函数)
构造函数规范:
如果添加构造函数,那就把无参的构造函数显示添加.添加构造函数的时候使用@AutoWired注解
3 setter方法注入
如果不加@Autowired,报错了,任然是空指针异常
3.1.4 三种注入的优缺点(面试八股文)
1. 属性注入
优点: 简介,使用方便
缺点: 只能用于IoC容器,非IoC容器不可以使用
不能注入一个final修饰的属性(也可以这么理解,后面setter方法一定会操控这个对象,对它进行赋值操作,那么final就不适合了)只有在使用的时候才会显示空指针异常.(idea不会给你爆红,运行之后才会有错误信息)
2. 构造函数注入(Spring4.x版本)
优点: 可以注入final修饰的属性
注入的对象不会被修改
依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的(去除@Autowired也可以)
3. Setter注入(Spring3.x推荐)
优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
缺点:不能注⼊⼀个Final修饰的属性
注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤, 就有被修改的⻛险.
上面是解释版本,下面是纯记版本
3.1.5 @Autowired存在问题
当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题
先来看看正确运行
我们使用属性注入,发现名称匹配不上就会根据类型来匹配,然后发现有三个这个类型的,不符合单例模式.
三种解决方式:
1. @Primary
通过@Primary,把其中一个Bean设置成一个默认的bean(注意下面的代码我在UserInfo属性上少加了@Autowired注解
2. @Qualifier
通过@Qualifier,指定哪个是默认的Bean
3. @Resource
通过@Resource注解,指定Bean
bean的重命名:
常⻅⾯试题(面试八股文):
他们都能实现对象的注入
@Autowird 与 @Resource的区别
1. @Autowired 是spring框架提供的注解,⽽@Resource是JDK提供的注解
2. @Autowired 默认是按照类型注⼊,⽽@Resource是按照名称注⼊. 相比于 @Autowired 来说,@Resource ⽀持更多的参数设置,例如 name 设置,根据名称获取 Bean。@Autowired,@Qualified的执行流程(自己演示一下)
Spring, Spring Boot 和Spring MVC的关系以及区别(八股文)
Spring 相当于火车,Spring MVC类似于售卖火车票(卖票肯定是基于火车这个条件的),一开始我们卖票就是在火车站线下买票.
Spring Boot类似于12306,它不仅具备线上卖票(比线下更高效)的功能,还封装了买保险,订酒店,订外卖...功能模块.
总而言之,一个项目有很多模块,Spring MVC是其中的一个模块,Spring Boot把包括Spring MVC的很多模块都封装起来了.简而言之: Spring Boot 是封装了更多功能,这个功能包含了Spring MVC的功能.也就是Spring Boot更加的高级.
Spring:高铁
Spring MVC(买票,坐车)
Spring Boot(类似于12306)通过pom文件集成了很多东西进来
总而言之: Spring MVC和Spring Boot都属于Spring,Spring MVC 是基于Spring的⼀个MVC 框架,⽽Spring Boot 是基于Spring的⼀套快速开发整合包.
之前的
他们之间的关系图:
Spring Core-> DI,IoC.这个是Spring的核心,Spring最原始的功能.对应的是Spring Framwork
Spring MVC,Spring Data JPA,Spring Security都是基于Spring Core来进行开发的
Spring Boot就是把上面的项目集成起来
上面整个就称作Spring家族
补充: Spring发展历史
微服务: 是一种架构风格,旨在将一个大型的单体应用拆分成多个独立的小服务,每个服务都可以独立运行和部署.
Spring MVC 的实现方式现在采用Spring Boot 早期是使用Spring Core加上很多配置来实现的.
比如在美团买火车票,要登录12306的账号,它是基于12306的二次开发.
pom文件的一些解释(一般版本号我们加入其他地方的依赖的时候,选择不加,不然容易引起版本冲突)
补充: idea快捷键:把鼠标放在类上按Shift+Fn+F6(快速改名)
Ctrl+alt+L java代码的格式化