Spring万字详解bean的实例化
Posted 续写青春.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring万字详解bean的实例化相关的知识,希望对你有一定的参考价值。
文章目录
前言
在上篇文章,我们已经完成了
入门案例
的学习,在入门案例中,我们讲了三块东西,首先是bean怎么定义配置,DI怎么去制作配置以及我们的容器对象如何去获取
在接下来的内容中,我们将针对以上三块东西展开学习✍️✍️。
1.bean实例化
1.1 bean的基础配置
- 在学习bean的实例化之前,我们先来学习
bean该如何配置
。
在bean的配置这一块,我们将学习
三块
内容,分别为:bean基础配置、bean别名配置、bean作用范围配置
。
- 我们先来看一下bean的基础配置👇👇
现在我们已经完成了基础配置的学习,
id
用来定义bean的名称,通过它可以获取,class
用来指定bean的类型,也就是你造出来的bean究竟是哪一个类的,那么这个时候就有一个问题了,对应的bean的id你写好了,但是你的命名习惯
和我的命名习惯不一样,我不想叫这个名称,有没有办法呢,这就是有关bean可以起多个名称
,也就是所谓的bean的别名
。
- 接下来我们来看bean的别名配置,在学习之前,我们先来交代一下当前的程序环境👇👇
service
层接口👇👇
service
层实现类👇👇
dao
层接口👇👇
dao
层实现类👇👇
applicationContext.xml
配置文件👇👇
主方法
👇👇
- 在了解了
程序环境
以后,我们开始来学习别名配置
🎉🎉。
我们知道bean的别名肯定是写在
applicationContext.xml
配置文件中的 ,怎么写呢,在配置的 bean中,有一个name
属性,可以为这个bean指定更多的名称👇👇。
注意
:别名可以有多个,使用逗号,分号,或者空格进行分隔。
当我们在
主方法
中将getBean()方法里边的参数改为我们配置的别名
,我们会发现程序还可以正常运行
,那就说明我们配置的别名是有效的。👇👇
接下来我们思考:我们在绑定
service与dao
的关系时,在service层配置的bean里边有一个属性ref
表示的是参照dao层配置的bean,属性值为dao层配置的bean的属性id
,那么如果我们将ref这个属性改为
我们在dao层配置的bean的别名,那么程序还可以正常运行吗?我们来演示一下👇👇
通过以上演示,我们可以得知别名的
作用范围
是很大的❗❗虽然我们学习了用别名配置bean的方式,但是还是建议我们ref参照
的时候,还是引用id属性
💪💪。
- 接下来需要说一说我们需要
注意
的问题了👇👇
回到我们的
主方法
中,我们现在在getBean()
方法中传递进去一个我们没有的参数service5
,这是在配置的service的bean中的id属性和name属性都没有
的参数,那我们运行的话会有什么问题呢👇👇
运行完会报出一个
异常
,这个异常的意思就是没有一个这样的bean被定义
,如果以后我们遇到这个异常的话,只需要检查我们的名字就行了👊👊
- bean的别名配置我们已经说完了,接下来我们来学习
bean的作用范围
👇👇
什么叫bean的作用范围呢?其实就是你现在创建的bean的究竟是
一个对象
还是多个对象
,什么意思呢,其实就是说你造的对象是单例
的还是非单例
的,我们先来看看如下代码👇👇
我们获取到BookDao的对象,并且打印它的
地址
👇👇
那我们将以上代码
复制两份
并且分别打印它们的地址,会出现什么结果呢👇👇
通过运行结果我们可以发现,两次打印的结果是
同一个地址
,那么它们也可以认为是同一个对象了
,由此得出:Spring默认给我们创建的bean是单例的
,那么这时候就有新问题了,如果我想要创建一个非单例的
该怎么办,这个时候就要通过配置
的方法解决这个问题了🎉🎉
如下,我们在dao层配置的bean后边再加一个
属性scope
,就是作用范围的意思,里边有两个值,一个singleton
表示单例的,一个prototype
表示非单例的,不写的话,默认
是signleton,我们设置scope属性为prototype,来看看运行结果👇👇
通过运行结果我们可以得出,此时的所创建的两个对象是
不同
的,注意
:我们上面所框出的是对象的哈希值
,不是对象的地址但是可以当做是对象的地址❗❗
- 在学完bean的作用范围,我们可以认为它是可以
控制
创建的bean是一个或者是多个的,那么新的问题来了,为什么bean默认是单例的
❓
我们来解释一下,对于
Spring
来说,它帮我们管理的bean要放到它的容器中,我们 假定一个场景,如果它造出来的bean不是
非单例的,那么这个bean的数量
会有多少呢?它会无穷无尽,用一次造一个,所以说Spring它并不是帮我们管理这一类bean的,这样的话,对Spring容器来说也有一个非常大的压力
,那Spring帮我们管理的bean都是单例
的,那会对我们的业务造成伤害吗,你想一想,你造一个dao对象,执行完一个方法,下一次你又需要造一个dao对象,再执行另一个方法,那我这两个对象用同一个不行吗?好像没有什么问题,就是这个原因,Spring容器在帮我们管理对象的时候其实就是在管理那些你可以复用
的对象,就是这个对象你用一次,下一次还用它,所以你下次还会从容器中拿,这样它的效率
才会更高
一些,因此,它就简单一点,给你造的bean就是单例
的❗❗。
- 那么新的问题有又来了,哪些bean适合
造单例
的呢❓
我们的
表现层
对象,比如说我们现在写的Servlet
,业务层
对象,Service
,数据层
对象,Dao
,或者还有一些工具类
的对象,这些对象,你造一次就ok了,就这个对象我可以反复用
,这些东西交给Spring管理
💪💪。
- 那哪些东西不适合交给Spring管理呢❓
封装实体的域对象
不适合交给Spring管理,因为它里边会记录
一些它的成员变量
的一些属性值
,到这里我们就知道了bean的作用范围
是控制
我们bean创建的实例的数量
的🎈🎈。
1.2 bean的实例化-构造方法
上面我们学习完了bean的基础配置
,那就有人问了,我们的这个单例bean是如何造出来的呢,和我们以前的写法一样吗,也是用new的方式造出来的吗,我们现在就来学习bean的实例化-构造方法实例化的方式
🎉🎉。
对于bean来说,其本质是
对象
,在前面我们说过,我们将容器中管理的对象叫做bean
,我们以前创造对象是怎么写:new跟构造方法
,对于Spring
来说,它也是通过构造方法来完成bean的创建的,一起来看一下👇👇
以上是我们程序的环境☝️☝️,接下来我们来说以前我们造对象
new+构造方法
,对于Spring来说,同样的道理,它也是用构造方法来造对象的。
接下来我们在
dao的实现类
中生成构造方法,并且在构造方法中打印一句话👇👇
什么都不动,我们再来运行一下,看看这句话执行了没有,如果执行了,那就意味着Spring容器调用了构造方法造对象👇👇
结果是用了,造对象都得用
构造方法
,在这说一个东西,我们将构造方法的权限修饰符改为private
,我们说如果以前我们写程序,把构造方法私有化以后,我们在外边还可以造对象吗?显然是绝对造不出来的,那我们再来运行一下👇👇
结果是不是
出人意料
啊,Spring还可以调用它的构造方法,那就说明了一点,Spring确实是通过构造方法
来造对象的,而且不管是公共的还是私有的它都能调到,我们可以猜到它的内部是怎么回事吗,私有的东西它居然可以访问,怎么做的,是通过反射
,后边我们在学习一些内部工作原理的时候,我们再来学习它,现在只需要知道它是通过构造方法造对象的就可以了,但是这个时候就有人提出来了一个问题,那万一给它加一个参数
呢?👇👇
我们来试一试,并且运行一下,会发现它已经不能正常运行了👇👇,这就说明了一点,Spring在创建bean的时候,调用的是
无参构造方法
,到这里我们就学习完了第一种实例化bean的方式,就是用构造方法来实例化对象
❗❗
1.3 bean的实例化-静态工厂
- 前面我们学习了用构造方法来实例化bean,接下来我们来说第二种方式,在学习第二种方式之前,我们先来回顾一个东西,我们在前边讲过,用
工厂
也可以造对象,我们先来看看程序环境
👇👇
- 接下来我提供了一个
工厂类
👇👇
- 如果用这个来写的话,会是什么样子的呢?接下来我们来看一下
先去使用工厂去获得这个对象,然后去运行,我们去运行一下👇👇
我们发现这是可以运行的,其实这是
早些年
做程序的一个常用的方式,说的简单一点就是造对象不要自己new,而是用工厂的方式做一定程度的解耦
,那么这种方式也是造对象的一种方式,如果我们的对象是用这样一种方式造出来的,交给Spring管理该怎么管呢?这就是我们要学习的第二种方式:用静态工厂来造对象
,接下来我们来学习以下该怎么做💪💪
对于它的接口实现类和静态工厂来说,这三个东西是一套东西,如果我们现在要管理这个bean,首先要写它的
配置文件
👇👇,那么问题来了,这样造出来的对象究竟是dao的对象还是factory的对象❓应该是factory的,因为你配什么造出来的就是什么,那我们要的是factory的对象吗?显然不是,我们要的是factory里边的方法造出来的dao对象,所以我们下面这么写肯定是不行的,我们除了要告诉它的工厂类,还要告诉它一个东西factory-method属性
来告诉它工厂是使用哪一个方法来造对象的,到这就可以造出来了,我们来运行一下,当然是用Spring的方式来运行的👇👇。
到这我们的第二种方式就学完了,但是还有一个问题,为什么不直接new啊,我们要知道工厂中做的有事情,可能会有一些配置👇👇,并且不能扔,所以强制你必须要用这个工厂,我们再来运行一下👇👇
1.4 bean的实例化-实例工厂与FactoryBean
- 接下来我们来学习第三种方式,首先我们来看看
程序环境
👇👇。
注意
:此时这个工厂是非静态的
。
- 在了解完程序环境后,我们就开始学习它
首先也是一样打开
配置文件
,我们在实例化的时候,必须先去造一个实例工厂类的对象,所以我们先来配置实例工厂类的bean👇👇
我们在造出这个工厂类的对象以后,我们再来配置dao层的bean👇👇,
属性factory-bean
指的是这个工厂的实例在哪呢,第二个是这个工厂用哪个方法来造这个对象的👇👇。
我们来用Spring的方式来运行一下👇👇
上边我们为了造dao层的对象,专门写了一个factory的bean,其实这个东西挺多余的,除了这个作用以外,无任何意义,还有在dao层的bean里边有一个
属性factory-method
,方法名不固定,每个里边都得指定,那么这种东西不能写一个通用的名称吗?针对以上问题,Spring就做了一次改良:FactoryBean
,我们先来看看程序环境👇👇
注意
:工厂造什么对象,就写什么泛型
,第二个方法返回的是对象的字节码文件
.
我们可能会发现,它和上边的好像没什么区别,但是它在
配置
的时候可简单
多了,我们接下来在配置文件中配bean
,并且看看是否可以正常运行👇👇
结果是可以正常运行,这就是我们所说的第三种方式的改良了,在这里我们覆盖了一个方法
isSingleton
,那接下来我们来看看,既然你造出来这个对象了,我们可以想一想,造出来的这个对象是单例的还是非单例,我们来通过getBean()
方法获得两个userDao对象,并且分别打印,接下来我们来看一下 👇👇
我们通过结果可以看出,通过这种方式造出来的对象是
单例的
,那么怎么样去改非单例的呢,我们在UserDaoFactoryBean
中加上isSingleton
方法,然后返回值设置为false
,就可以改成非单例
的了💪💪
我们再来运行一下,此时就变成
非单例
的了
总结
在本篇文章中,我们先来介绍了
bean的基础配置
,然后详细介绍了几种实例化bean的方式
,下篇文章我们将要学习bean的生命周期
,最后,如果有什么错误的话,大家可以私信我📬📬,希望大家多多关注+点赞+收藏 ^_^🙏🙏,你们的鼓励是我不断前进的动力💪💪!!!
以上是关于Spring万字详解bean的实例化的主要内容,如果未能解决你的问题,请参考以下文章
猿创征文|13万字学会Spring+SpringMVC+Mybatis框架