Bean的配置
Spring可以被看作是一个大型工厂,这个工厂的作用就是生产和管理Spring容器中的Bean。
如果想要在项目中使用这个工厂,就需要开发者对Spring的配置文件进行配置。
Spring容器支持XML和Properties两种格式的配置文件,在实际开发中,最常使用的就是XML格式的配置文件。这种配置方式通过XML文件来注册并管理Bean之间的依赖关系。
在Spring中,XML配置文件的根元素是<beans>,<beans>中包含了多个<bean>子元素,每一个<bean>子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。
<bean>元素中同样包含了多个属性以及子元素,如下等:
属性或子元素名称 | 描述 |
id | 是一个Bean的唯一标识符,Spring容器对Bean的配置、管理都通过该属性来完成 |
name | 同样通过此属性对Bean进行配置和管理,name属性中可以为Bean指定多个名称,每个名称之间用逗号或分号隔开 |
class | 该属性指定了Bean的具体实现类,它必须是一个完整的类名、实用类的全限定名 |
ref | 可以用于指定Bean工厂中某个Bean实例的引用 |
上面的表格中只是列表了部分常用的,通常一个普通的Bean只需要定义 id(或name)和 class两个属性即可。例如:
<bean id="accountDao" class="com.dfbz.dao.imp.AccountDaoImpl"></bean>
注意:如果在Bean中未指定 id 和 name ,则Spring会将class值当作id使用
Bean的实例化
在面向对象的程序中,想要使用某个对象,就需要先实例化这个对象。同样,在Spring中,要想使用容器中的Bean,也需要实例化Bean。
实例化Bean有三种方式:构造器实例化、静态工厂方式实例化、实例工厂方式实例化
构造器实例化(常用)
构造器实例化是指Spring容器通过Bean对应类中默认的无参构造方法来实例化Bean。
<bean id="studentService" class="com.dfbz.service.Impl.StudentServiceImpl"></bean>
在Spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造函数创建bean对象。
静态工厂方式实例化
该方式要求开发者创建一个【静态工厂的方法来创建Bean的实例】,其Bean配置中的class属性所指定的不再是Bean实例的实现类,而是静态工厂类,同时还需要使用 factory-method属性来指定所创建的静态工厂方法。
public class StaticFactory {
public static AccountService getAccountService(){
return new AccountServiceImpl();
}
}
配置文件:
<bean id="accountService" class="cn.itcast.factory.StaticFactory"
factory-method="getAccountService">
</bean>
class:静态工厂类的全路径类名
factory-method:静态工厂类中的方法名
通过factory-method属性来告诉Spring容器,方法名称是:getAccountService
实例工厂方式实例化
在这种方式的工厂类中,不再使用静态方法创建Bean实例,而是采用直接创建Bean实例的方式。
同时在配置文件中,需要实例化的Bean也不是通过class属性直接指向的实例化类,而是通过factory-bean属性指向配置的实例工厂,然后使用factory-method属性确定使用工厂中的哪个方法。
public class InstanceFactory {
public AccountService getAccountService(){
return new AccountServiceImpl();
}
}
<bean id="instanceFactory" class="cn.itcast.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory"
factory-method="getAccountService"></bean>
在配置文件中,首先配置一个工厂Bean,然后配置了需要实例化的Bean。
在id为accountService的Bean中,使用 factory-bean属性指定配置的实例工厂,该属性就是工厂Bean的id,使用 factory-method属性来确定使用工厂中的 getAccountService方法。
Bean的作用域
通过Spring容器创建一个Bean的实例时,不仅可以完成Bean的实例化,还可以为Bean指定特定的作用域。
Bean标签的scope属性:用于指定bean的作用范围
作用域的种类
singleton(默认)、 prototype 是最常用的两种
作用域名称 | 说明 |
singleton(单例) | 使用singleton定义的Bean在Spring容器中将只有一个实例,也就说,无论有多少个Bean引用它,始终将指向同一个对象 |
prototype(多例) | 每次通过Spring容器获取的prototype定义的Bean时,容器都将创建一个新的Bean实例 |
singleton(共享)
singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean的id属性相同,就会返回同一个Bean实例。singleton作用域对于无会话状态的Bean来说,是最理想的选择。
在Spring配置文件中,Bean的作用域是通过<bean>元素的scope属性来指定的,该属性值可以设置为 singleton、prototype、request、session、globalSession、application 和 websocket 七个值。
<bean id="studentService" class="com.dfbz.service.Impl.StudentServiceImpl" scope="singleton">
</bean>
注意:如果不设置 scope = “singleton”,其输出结果也是同一个实例,因为Spring容器默认的作用域就是 singleton。
prototype(创建新的)
对需要保持会话状态的Bean应该使用prototype作用域。在使用 prototype作用域时,Spring容器会为每个对该Bean的请求都创建一个新的实例。
<bean id="studentService" class="com.dfbz.service.Impl.StudentServiceImpl" scope="prototype">
</bean>
Bean的生命周期
Spring根据Bean的作用域来选择管理方式。
对于 singleton 作用域的Bean,Spring能够精确地知道该Bean何时被创建,何时初始化完成,以及何时被销毁;
对于 prototype 作用域的Bean,Spring只负责创建,当容器创建了Bean的实例后,Bean的实例就交给客户端代码管理,Spring容器将不再跟踪其生命周期。
单例对象:
- 出生:当容器创建时对象出生
- 活着:只要容器还在,对象一直活着
- 死亡:容器销毁,对象死亡
- 总结:单例对象的生命周期和容器相同
多例对象:
- 出生:当使用对象时Spring框架
- 活着:对象只要是在使用过程中就一直活着
- 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
Bean 的定义 -> Bean 的初始化 -> Bean 的使用 -> Bean 的销毁
在Spring中,Bean生命周期的执行是一个很复杂的过程,可以利用Spring提供的方法来定制Bean的创建过程。当一个Bean被加载到Spring容器时,它就具有了生命。而Spring容器在保证一个Bean能够使用之前,会做很多工作。
Spring容器中的Bean的生命周期流程如下图:
Bean的生命周期的整个执行过程描述如下:
- Spring启动,查找并加载需要被Spring管理的Bean,进行Bean的实例化(调用Bean构造方法或工厂方法实例化)
- 利用依赖注入完成Bean中所有属性值的配置注入
- 如果Bean实现了BeanNameAware接口的话,则Spring调用Bean的 setBeanName()方法传入当前的Bean的id值
- 如果Bean实现了BeanFactoryAware接口的话,则Spring调用 setBeanFactory()方法传入当前工厂实例的引用
- 如果Bean实现了ApplicationContextAware接口的话,则Spring调用Bean的 setApplicationContext()方法传入当前ApplicationContext实例的引用
- 如果 BeanPostProcessor 和 Bean 关联,则Spring将调用该接口的预初始化方法postProcessBeforeInitialization()对 Bean 进行加工操作,这个非常重要,Spring的AOP就是用它实现的。
- 如果Bean实现了InitializingBean接口,则Spring将调用afterPropertiesSet()方法。类似的,如果在配置文件中通过 Bean使用init-method属性指定了初始化方法,则调用该初始化方法
- 如果 BeanPostProcessor 和 Bean 关联,则Spring将调用该接口的初始化方法postProcessAfterInitialization()方法。此时,Bean已经可以被应用系统使用了
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文,直到应用上下文被销毁。如果该Bean的作用范围是【singleton】,则将Bean放入SpringIOC的缓冲池中,将触发Spring对该Bean的生命周期管理;如果该Bean的的作用范围是【prototype】,则将该Bean交给调用者,调用者管理该Bean的生命周期,Spring不再管理该Bean。
- 如果Bean实现了DisposableBean接口,则Spring会调用destory()方法将Spring中的Bean销毁;同样,如果在配置文件中Bean通过destory-method属性指定Bean的销毁方法,则Spring将调用该方法进行销毁