摘要:在利用Spring进行IOC配置时,对于bean的配置和应用始终都是比拟重要的一部分,同时如何正当的应用和创立bean对象,也是小伙伴们在学习和应用Spring时须要留神的局部,所以这一篇文章我就来和大家讲一下无关Spring中bean的作用域和其生命周期。
本文分享自华为云社区《详解Spring中Bean的作用域与生命周期》,原文作者:灰小猿。
在利用Spring进行IOC配置时,对于bean的配置和应用始终都是比拟重要的一部分,同时如何正当的应用和创立bean对象,也是小伙伴们在学习和应用Spring时须要留神的局部,所以这一篇文章我就来和大家讲一下无关Spring中bean的作用域和其生命周期。
一、Bean的作用域
首先咱们来讲一下有对于bean的作用域,
个别状况下,咱们书写在IOC容器中的配置信息,会在咱们的IOC容器运行时被创立,这就导致咱们通过IOC容器获取到bean对象的时候,往往都是获取到了单实例的Bean对象,
这样就意味着无论咱们应用多少个getBean()办法,获取到的同一个JavaBean都是同一个对象,这就是单实例Bean,整个我的项目都会共享这一个bean对象。
在Spring中,能够在<bean>元素的scope属性里设置bean的作用域,以决定这个bean是单实例的还是多实例的。Scope属性有四个参数,具体的应用能够看下图:
1、单实例Bean申明
默认状况下,Spring只为每个在IOC容器里申明的bean创立惟一一个实例,整个IOC容器范畴内都能共享该实例:所有后续的getBean()调用和bean援用都将返回这个惟一的bean实例。该作用域被称为singleton,它是所有bean的默认作用域。也就是单实例。
为了验证这一说法,咱们在IOC中创立一个单实例的bean,并且获取该bean对象进行比照:
<!-- singleton单实例bean 1、在容器创立时被创立 2、只有一个实例 --><bean id="book02" class="com.spring.beans.Book" scope="singleton"></bean>
测试获取到的单实例bean是否是同一个:
@Testpublic void test09() { // 单实例创立时创立的两个bean相等 Book book03 = (Book)iocContext3.getBean("book02"); Book book04 = (Book)iocContext3.getBean("book02"); System.out.println(book03==book04);}
失去的后果是true;
2、多实例Bean申明
而既然存在单实例,那么就肯定存在多实例。咱们能够为bean对象的scope属性设置prototype参数,以示意该实例是多实例的,同时获取IOC容器中的多实例bean,再将获取到的多实例bean进行比照,
<!-- prototype多实例bean1、在容器创立时不会被创立,2、只有在被调用的时候才会被创立3、能够存在多个实例 --><bean id="book01" class="com.spring.beans.Book" scope="prototype"></bean>
测试获取到的多实例bean是否是同一个:
@Testpublic void test09() { // 多实例创立时,创立的两个bean对象不相等 Book book01 = (Book)iocContext3.getBean("book01"); Book book02 = (Book)iocContext3.getBean("book01"); System.out.println(book01==book02);}
失去的后果是false
这就阐明了,通过多实例创立的bean对象是各不相同的。
在这里须要留神:
同时对于单实例和多实例bean的创立也有不同,当bean的作用域为单例时,Spring会在IOC容器对象创立时就创立bean的对象实例。而当bean的作用域为prototype时,IOC容器在获取bean的实例时创立bean的实例对象。
二、Bean的生命周期
1、bean的初始和销毁
其实咱们在IOC中创立的每一个bean对象都是有其特定的生命周期的,在Spring的IOC容器中能够治理bean的生命周期,Spring容许在bean生命周期内特定的工夫点执行指定的工作。如在bean初始化时执行的办法和bean被销毁时执行的办法。
Spring IOC容器对bean的生命周期进行治理的过程能够分为六步:
- 通过结构器或工厂办法创立bean实例
- 为bean的属性设置值和对其余bean的援用
- 调用bean的初始化办法
- bean能够失常应用
- 当容器敞开时,调用bean的销毁办法
那么对于bean的初始和销毁时执行的办法又该如何申明呢?
首先咱们应该在bean类外部增加初始和销毁时执行的办法。如上面这个javabean:
package com.spring.beans;public class Book { private String bookName; private String author; /** * 初始化办法 * */ public void myInit() { System.out.println("book bean被创立"); } /** * 销毁时办法 * */ public void myDestory() { System.out.println("book bean被销毁"); } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } @Override public String toString() { return "Book [bookName=" + bookName + ", author=" + author + "]"; }}
这时咱们在配置bean时,能够通过init-method和destroy-method 属性为bean指定初始化和销毁办法,
<!-- 设置bean的生命周期destory-method:完结调用的办法init-method:起始时调用的办法 --><bean id="book01" class="com.spring.beans.Book" destroy-method="myDestory" init-method="myInit"></bean>
这样当咱们在通过IOC容器创立和销毁bean对象时就会执行相应的办法,
然而这里还是有一点须要留神:
咱们下面说了,单实例的bean和多实例的bean的创立工夫是不同的,那么他们的初始办法和销毁办法的执行工夫就稍稍有不同。
- 单实例下 bean的生命周期
容器启动——>初始化办法——>(容器敞开)销毁办法
- 多实例下 bean的生命周期
容器启动——>调用bean——>初始化办法——>容器敞开(销毁办法不执行)
2、bean的后置处理器
什么是bean的后置处理器?bean后置处理器容许在调用初始化办法前后对bean进行额定的解决
bean后置处理器对IOC容器里的所有bean实例逐个解决,而非繁多实例。
其典型利用是:查看bean属性的正确性或依据特定的规范更改bean的属性。
bean后置处理器应用时须要实现接口:
org.springframework.beans.factory.config.BeanPostProcessor。
在初始化办法被调用前后,Spring将把每个bean实例别离传递给上述接口的以下两个办法:postProcessBeforeInitialization(Object, String)调用前
postProcessAfterInitialization(Object, String)调用后
如下是一个实现在该接口的后置处理器:
package com.spring.beans;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;/** * 测试bean的后置处理器 * 在这里要留神一点是为了呈现bean和beanName,而不是arg0、arg1,须要绑定相应的源码jar包 * */public class MyBeanPostProcessor implements BeanPostProcessor{ /** * postProcessBeforeInitialization * 初始化办法执行前执行 * Object bean * String beanName xml容器中定义的bean名称 * */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("【"+ beanName+"】初始化办法执行前..."); return bean; } /** * postProcessAfterInitialization * 初始化办法执行后执行 * Object bean * String beanName xml容器中定义的bean名称 * */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("【"+ beanName+"】初始化办法执行后..."); return bean; }}
将该后置处理器退出到IOC容器中:
<!-- 测试bean的后置处理器 --><bean id="beanPostProcessor" class="com.spring.beans.MyBeanPostProcessor"></bean>
因为当初咱们的bean对象是单实例的,所以容器运行时就会间接创立bean对象,同时也会执行该bean的后置处理器办法和初始化办法,在容器被销毁时又会执行销毁办法。咱们测试如下:
//*************************bean生命周期*****************// 因为ApplicationContext是一个顶层接口,外面没有销毁办法close,所以须要应用它的子接口进行接管 ConfigurableApplicationContext iocContext01 = new ClassPathXmlApplicationContext("ioc1.xml"); @Test public void test01() { iocContext01.getBean("book01"); iocContext01.close(); }
运行后果:
总结一下后置处理器的执行过程:
- 通过结构器或工厂办法创立bean实例
- 为bean的属性设置值和对其余bean的援用
- 将bean实例传递给bean后置处理器的postProcessBeforeInitialization()办法
- 调用bean的初始化办法
- 将bean实例传递给bean后置处理器的postProcessAfterInitialization()办法
- bean能够应用了
- 当容器敞开时调用bean的销毁办法
所以增加bean后置处理器后bean的生命周期为:
容器启动——后置处理器的before...——>初始化办法——>后置处理器的after...———>(容器敞开)销毁办法
点击关注,第一工夫理解华为云陈腐技术~