目录

SpringSpringIOC详解,包括源码分析,xml以及注解开发

【Spring】SpringIOC详解,包括源码分析,xml以及注解开发

SpringIOC

Spring简介

​ Spring是一个开源框架,它由 创建。它是为了解决企业应用开发的复杂性而创建的。

​ 目前是JavaEE开发的灵魂框架。他可以简化JavaEE开发,可以非常方便 整合其他框架无侵入的进行功能增强

​ Spring的核心就是 控制反转(IoC)和面向切面(AOP) 。

IOC控制反转

控制反转,之前对象的控制权在类手上,现在反转后到了Spring手上。

具体步骤

导入依赖

https://i-blog.csdnimg.cn/img_convert/4c72cc443d6896e44ca630f521267a02.png

编写配置文件

https://i-blog.csdnimg.cn/img_convert/beb54df6b54f11f374849bddef5aa28f.png

https://i-blog.csdnimg.cn/img_convert/b27c0fda7a7a087fc552c66a46922c3a.png

https://i-blog.csdnimg.cn/img_convert/2796858ff5996305c6d5dab28a0658fe.png

创建容器对象获取实现类对象完成测试

https://i-blog.csdnimg.cn/img_convert/6b2287923acd289f4e89a57892d1a38f.png


Bean的属性

https://i-blog.csdnimg.cn/img_convert/04d10148b7feeba090ed8b095b10e0c7.png

https://i-blog.csdnimg.cn/img_convert/7a7f6d8edd0a6a036d39fb6a768ef473.png

scope

https://i-blog.csdnimg.cn/img_convert/7f6bccec68b48283329d0370a7dec3d4.png

单例模式下

执行第一句话创建容器的时候就会创建实现类对象

之后执行getBean方法不会创建

多例模式下

执行第一句话不会创建实现类对象

之后每执行一次getBean方法,创建一次对象


spring源码分析

https://i-blog.csdnimg.cn/img_convert/75244f11d82aadf150271591bf3d1f50.png

测试方法中创建了 ioc容器的对象 ,传入了beans.xml的path参数

调用getBean方法传入接口名,获得接口实现类对象,来调用实现类接口


classPathXmlApplicationContext容器源码

https://i-blog.csdnimg.cn/img_convert/9a71dade2329f37fb183b4e90fa1f555.png

创建了一个HashMap集合来存放对象


load方法

https://i-blog.csdnimg.cn/img_convert/d3558ec9757dad5b491b77dbd45cc0f7.png

document内容

https://i-blog.csdnimg.cn/img_convert/d962428b8811630d94cdc3e9dacb65ae.png

获取标签中的calss和id值

https://i-blog.csdnimg.cn/img_convert/0c811acdbb17d6c0ee0ece144836c64b.png

通过反射机制创建对象

https://i-blog.csdnimg.cn/img_convert/a1f9c345095c4c0d5549c421574a0e64.png

id作为key ,创建出来的 对象作为value 存进最开始的beanMap集合中

https://i-blog.csdnimg.cn/img_convert/da17254f009989c0526ab5d416d45c1e.png

到这里 第一句创建对象就结束了

第二句getBean传入id参数

就是从beanMap中根据id获取对象

https://i-blog.csdnimg.cn/img_convert/4846f6673487e9409603300fb3743b09.png

这里就完成了对象创建的解耦合

可以直接修改xml文件里的impl名

这里就可以直接newIOC容器传入beans.xml文件和id就可以获取到实现类对象了

https://i-blog.csdnimg.cn/img_convert/a0851d77fa5df6cb3d336401fc756ccb.png


DI依赖注入

一些实现类比如service的实现类里面一般有dao的属性值好来调用crud

https://i-blog.csdnimg.cn/img_convert/37e5fc2addbb6a9bfc178b2d37ebb84a.png

比如这里service的实现类里面有dao的属性值

但是我们通过ioc创建对象的时候,没有给这些属性值赋值, 默认为null

当需要用到userDao来调用方法的时候

会报空指针异常错误,就 需要通过DI依赖注入的方式来给这些属性值初始化


Set方法注入

我们平时给属性值赋值的时候一般有两种方法

  • 空参创建出对象,来调用set方法赋值
  • 直接有参构造创建对象

可以在bean标签内用property标签来给属性值赋值

https://i-blog.csdnimg.cn/img_convert/3a24b327a339b0d63b0528f75d88a67e.png

这里其实就是调用了实现类的set方法, 如果实现类没有set方法,则报错


ref引用数据类型赋值

假设我们在student里面创建一个dog类型的属性

可以在ref标签中写上spring容器中bean的id来注入

https://i-blog.csdnimg.cn/img_convert/909adda56fa5807b4935d179b65d1f94.png


有参方法注入

https://i-blog.csdnimg.cn/img_convert/a0aff54d293dd2e7cf3838d5e76b532e.png

https://i-blog.csdnimg.cn/img_convert/85336e7e323140859bfbe24436e653c1.png


复杂类型注入

实体类如下

https://i-blog.csdnimg.cn/img_convert/a296de05c29522043046415ac9038edf.png

https://i-blog.csdnimg.cn/img_convert/ce0662c0eee58b83365bd80021806be3.png

配置如下

Phone注入

https://i-blog.csdnimg.cn/img_convert/9f84cb41c83215460f7901630f6f4b46.png

List集合注入

https://i-blog.csdnimg.cn/img_convert/927bcd5b8ce006133e8e474689e3b26b.png

List集合注入

https://i-blog.csdnimg.cn/img_convert/01e39a0ea31b4e0a96e6a212753839ff.png

Set注入

https://i-blog.csdnimg.cn/img_convert/467e1e88746d9e8a621013987d8657ba.png

Map<String,Phone>注入

https://i-blog.csdnimg.cn/img_convert/f63698f976dd0c9489996aff415cb962.png

数组int[]注入

https://i-blog.csdnimg.cn/img_convert/f715838346657a37dee38b14ef2c198b.png

properties类型注入

https://i-blog.csdnimg.cn/img_convert/a68188db3bc52a088aae18a0ec7f8174.png

小技巧:

先写标签,空格看有没有可以写的属性,没有就结束标签,继续空格看有没有,有的话就写在标签内,没有就写在标签外


SPEL表达式

https://i-blog.csdnimg.cn/img_convert/212f6d8545d69547aa462fd262d42490.png

可以进行简单的计算value=“#{10+10}”

ref=“car” 等价于value=“#{car}”


Lombok插件

引入依赖

https://i-blog.csdnimg.cn/img_convert/88a8bd5c821ec51fe62286d31dd7d662.png

安装插件

https://i-blog.csdnimg.cn/img_convert/243ac51e486e77ce28ac34c4aaae7728.png

使用方法

https://i-blog.csdnimg.cn/img_convert/1694d66c9b5c3533ff751fe562edc5b5.png

在JavaBean中使用

@Data就是编译时自动生成get,set,toString,Hashcode,equals等方法

@NoArgsConstructor 空参构造

@AllArgsConstructor 带参构造


bean读取配置文件注入

举例

DruidDataSource数据库连接池对象

https://i-blog.csdnimg.cn/img_convert/41cb9107a4505dbfaf572cce56787634.png

引入依赖

https://i-blog.csdnimg.cn/img_convert/4293f47c729a8b8ebe0fcaf76af23cbe.png

正常连接步骤,new连接池对象,set设置连接参数

https://i-blog.csdnimg.cn/img_convert/5f16cfb90fcea7dc77256eb59fdb83cf.png

可以丢给xml文件的bean来帮我们new对象并且注入值


JDBC配置文件

https://i-blog.csdnimg.cn/img_convert/19aa2db0b7b04a9f75c21bf0480a0094.png

https://i-blog.csdnimg.cn/img_convert/55321244c147c6b87bbb2cda9668b623.png

因为我们编译的时候,resource文件下的配置文件都会自动放到target目录的classes目录下

https://i-blog.csdnimg.cn/direct/27f5c5a2d48f4b6493a1d9680399a29d.png

完整步骤

https://i-blog.csdnimg.cn/img_convert/362af4fd267ea3e876c89ad0abf91551.png


引入其他xml配置文件

当我们项目比较大的时候,会有很多个xml文件

所以需要有一个主的xml文件来 引入其他的xml文件

比如上文的数据库连接的xml文件就可以单独放到一个jdbc.xml文件中

然后在主配置文件中引入这个jdbc.xml文件

https://i-blog.csdnimg.cn/img_convert/0abd34fce682693b3992ef093c803bf8.png


低频知识点

bean的配置

name属性

也可以通过name来给bean取名字,name可以有多个

https://i-blog.csdnimg.cn/img_convert/f64731b1a079b6a3bad471ee3ca83ba0.png

lazy-init

当我们是默认是单例模式的情况下, 创建容器的时候就会创建实现类对象 ,之后执行getBean方法不会创建

使用lazy-init=“true"的时候, 创建容器的时候不会创建实现类对象 ,之后执行getBean方法创建

https://i-blog.csdnimg.cn/img_convert/7db2276b6692d870da767fc098797d2e.png

init-method

创建实现类对象的时候,spring会帮我们自动调用某一个方法,但是 必须是空参的!

https://i-blog.csdnimg.cn/img_convert/0c1d8734f063844bab8fd47829b504a7.png

destroy-method

当对象 销毁前 的时候,自动调用方法,也 必须是空参的

什么时候对象会销毁呢**,单例模式下**,只有 容器销毁的时候,对象才会销毁

我们也可以调用.close()来关闭容器

https://i-blog.csdnimg.cn/img_convert/5e268eac1c3357630e075a8b839d0c60.png

https://i-blog.csdnimg.cn/img_convert/7c647e4042cd9c6042acf47262d3c39d.png


工厂类

这是一个car的类,里面有三个引用类型的属性,每个属性都有一个测试方法来调试

https://i-blog.csdnimg.cn/img_convert/82a322fe87fdbf9c53e04dfd07722756.png

当我们需要得到一辆车的时候,需要new Car,然后set属性,最后还要调试

https://i-blog.csdnimg.cn/img_convert/8090a865648c2c40aa79ec4e448e7564.png

我们可以把这段代码封装到一个工厂类的getCar方法中

https://i-blog.csdnimg.cn/img_convert/c09805a51439808b0bc324bb145d1651.png

在主方法中就可以直接创建这个工厂类,来 调用getCar方法 ,获得一辆车

https://i-blog.csdnimg.cn/img_convert/a6750b71b623cea6c01a5cff8c81e7c7.png

这属于 实例工厂 ,因为方法不是静态的,需要创建对象,才能getCar

我们可以 把getCar方法设置成静态方法 ,就可以直接用类名来调用,这属于静态工厂

https://i-blog.csdnimg.cn/img_convert/99558a3773b44cbe3549dbb872517095.png


spring使用工厂类
实例工厂创建对象

https://i-blog.csdnimg.cn/img_convert/1cbaa351d8c4800152c31503824c9541.png

我们可以让spring来执行上面这些代码

配置文件中先设置工厂类

再设置一个bean,但是这个 bean没有class

factory-bean:指定使用哪个工厂对象

factory-method:指定使用哪个工厂方法

https://i-blog.csdnimg.cn/img_convert/37d2e9451a404f10e557cecc38af43f1.png

测试类中

https://i-blog.csdnimg.cn/img_convert/13b0ba6dceb5607d3a92c7275cf45823.png

这里 getBean使用的id是car


静态工厂创建对象

https://i-blog.csdnimg.cn/img_convert/3212524f2b871a49e5351cfbed81212c.png

不需要创建工厂对象了

配置文件中class指定工厂类的全类名,然后factory-method指定使用哪个工厂方法,要有一个id属性

https://i-blog.csdnimg.cn/img_convert/85ad4645e9dc03a4881d566eabe65b67.png

测试类中

https://i-blog.csdnimg.cn/img_convert/839f57bf1ca380eaed42822e6645c6ed.png


注解开发

@ component

https://i-blog.csdnimg.cn/img_convert/8ad0c13808b3ff8627cfacf27d21204a.png

等价于<bean…id=“student”>

前提在配置文件中添加component-scan

https://i-blog.csdnimg.cn/img_convert/265ede3f3d86facb3fcb841eca9932a1.png

https://i-blog.csdnimg.cn/img_convert/95aa2c99ac08e2d1b8290a4e13354d82.png

DI注解

简单属性注入**@value(“”)**

https://i-blog.csdnimg.cn/img_convert/e5cf55fd8d61b0dc0a86cfbe766a058b.png

支持SPEL写法#{}


@ Autowired

引用数据类型注入(就是从spring容器中找满足这个类型的注入)

https://i-blog.csdnimg.cn/img_convert/2900aa699af705d5d99a8595a4250997.png

前提: 本类和引用类都要被注解修饰(放到spring容器里面才能被找到)

https://i-blog.csdnimg.cn/img_convert/574135e8b0da5841ac9e28af36343055.png


required 属性代表这个属性是否是必须的,默认值为true。

如果是true的话Spring容器中如果找不到相同类型的对象完成属性注入就会出现异常。

https://i-blog.csdnimg.cn/img_convert/4ab927118afb43a08fb7f5e1be2ad668.png

如果改为false,就是找不到也无所谓,不报错,但是不会赋值,就是null


@ Qualifier

当一个包下面有多个 同类型的对象 时候,@Autowired找不到,就需要@Qualifier来 指定某一个对象的具体id

https://i-blog.csdnimg.cn/img_convert/6746fc1c923b15a3bbfc00b8f173f29c.png

需要和@Autowired连用


替换xml文件

自定义创建一个ApplicationConfig配置类

https://i-blog.csdnimg.cn/img_convert/583e7e93a003fc5e81c9a3b9970119cc.png

@ Configuration

标注在类上,表示当前类是一个配置类。我们可以用注解类来完全替换掉xml配置文件。

注意:如果使用配置类替换了xml配置,spring容器要使用:AnnotationConfigApplicationContext

测试类

https://i-blog.csdnimg.cn/img_convert/e50bfea95a825735a7bb3932ebbbfd26.png

@ ComponentScan

可以用来代替context:component-scan标签来配置组件扫描。

basePackages属性来指定要扫描的包。


Bean注解

和@component@Service@Repository一样

都是代替标签放到spring容器中的,但是@Bean主要是用来 导入第三方类的

比如DruidDataSource类

xml文件中

https://i-blog.csdnimg.cn/img_convert/0c787e7cef5e5990e61ba922063ff044.png

ApplicationConfig配置类导入

使用:定义一个方法,在方法中创建对应的对象并且作为返回值返回。然后在 方法上加上@Bean注解 ,注解的value属性来设置bean的名称。

https://i-blog.csdnimg.cn/img_convert/483eb9ab8779a559bc08a4662d784935.png


如何选择?

https://i-blog.csdnimg.cn/img_convert/cf3f05ab8b4ed7477d5f2a8db00a53d3.png