Life Cycle Management of a Spring Bean

原文地址:http://javabeat.net/life-cycle-management-of-a-spring-bean/

1) Introduction

This article would brief about how a Spring Bean is managed in IOC (Inversion of Control) Container. Spring Beans exist within the Container as long as they are needed by the Application. There are various life-cycle interfaces and methods that will be called by the IOC Container. The pre-requisite for this article is some basic knowledge in Spring which can be got by reading the article in Javabeat Introduction to Spring Web Framework.

2) Bean Life Cycle

Spring Bean represents a POJO component performing some useful operation. AllSpring Beans reside within a Spring Container also known as IOC Container. The Spring Framework is transparent and thereby hides most of the complex infrastructure and the communication that happens between the Spring Container and the Spring Beans. This section lists the sequence of activities that will take place between the time of Bean Instantiation and hand over of the Bean reference to the Client Application.

  1. The Bean Container finds the definition of the Spring Bean in the Configuration file.
  2. The Bean Container creates an instance of the Bean using Java Reflection API.
  3. If any properties are mentioned, then they are also applied. If the property itself is a Bean, then it is resolved and set.
  4. If the Bean class implements the BeanNameAware interface, then the setBeanName()method will be called by passing the name of the Bean.
  5. If the Bean class implements the BeanClassLoaderAware interface, then the methodsetBeanClassLoader() method will be called by passing an instance of theClassLoader object that loaded this bean.
  6. If the Bean class implements the BeanFactoryAware interface, then the methodsetBeanFactory() will be called by passing an instance of BeanFactory object.
  7. If there are any BeanPostProcessors object associated with the BeanFactory that loaded the Bean, then the method postProcessBeforeInitialization() will be called even before the properties for the Bean are set.
  8. If the Bean class implements the InitializingBean interface, then the methodafterPropertiesSet() will be called once all the Bean properties defined in the Configuration file are set.
  9. If the Bean definition in the Configuration file contains a 'init-method' attribute, then the value for the attribute will be resolved to a method name in the Bean class and that method will be called.
  10. The postProcessAfterInitialization() method will be called if there are any Bean Post Processors attached for the Bean Factory object.
  11. If the Bean class implements the DisposableBean interface, then the methoddestroy() will be called when the Application no longer needs the bean reference.
  12. If the Bean definition in the Configuration file contains a 'destroy-method'attribute, then the corresponding method definition in the Bean class will be called.

3) Life Cycle phases

3.1) Bean Name Aware Interface

If the Bean Implementation class wants to know the name of the Bean as configured and maintained by the Bean Factory class, then the Bean class should implement the interface BeanNameAware and override the setBeanName() method. The Bean Factory after reading the Bean definition from the Configuration file will come to know the name of the Bean and will pass this name as an argument to the setBeanName() method.

package javabeat.net.articles.spring.lifecycle;import org.springframework.beans.factory.BeanNameAware;public class LanguageBean implements BeanNameAware
{private String languageName;private String beanName;public LanguageBean(){}public String getLanguageName(){return languageName;}public void setLanguageName(String languageName){this.languageName = languageName;}@Overridepublic void setBeanName(String beanName){this.beanName = beanName;}public String getBeanName(){return beanName;}
}

The above sample class provides one such implementation and the below client code uses the above class to know the name of the bean.

static void beanNameAwareTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");BeanFactory beanFactory = new XmlBeanFactory(resource);LanguageBean javaLanguage = (LanguageBean)beanFactory.getBean("javaLanguage");System.out.println(javaLanguage.getLanguageName());System.out.println(javaLanguage.getBeanName());
}

The following piece of Xml code snippet goes into the Xml Configuration file.

<bean id="javaLanguage"><property name="languageName" value="Java"/>
</bean>

3.2) Bean Class Loader Aware Interface

package javabeat.net.articles.spring.lifecycle;import org.springframework.beans.factory.BeanClassLoaderAware;public class TestBeanWithClassLoaderAware implements BeanClassLoaderAware
{private ClassLoader classLoader;@Overridepublic void setBeanClassLoader(ClassLoader classLoader){this.classLoader = classLoader;}public ClassLoader getBeanClassLoader(){return classLoader;}
}

At times, a Client Application may wish to know the details of the Class Loader through which Bean objects are loaded. In such a case, the Bean class should implement theBeanClassLoaderAware interface and override the setBeanClassLoader() method. TheBean Factory object will pass an instance of the ClassLoader object that loaded this Bean to the setBeanClassLoader() method.

static void beanClassLoaderAwareTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");BeanFactory beanFactory = new XmlBeanFactory(resource);TestBeanWithClassLoaderAware classLoaderAwareBean =(TestBeanWithClassLoaderAware)beanFactory.getBean("classLoaderAwareBean");ClassLoader beanClassLoader = classLoaderAwareBean.getBeanClassLoader();System.out.println(beanClassLoader.getClass());
}

The above client program uses the TestBeanWithClassLoaderAware object and the following is the Xml configuration information for the above Spring Bean.

<bean id="classLoaderAwareBean" class="javabeat.net.articles.spring.lifecycle.TestBeanWithClassLoaderAware">
</bean>

3.3) Bean Factory Aware Interface

Bean Factory object is responsible for loading and creating Bean instances. This object is sufficient for simple cases. However situations may demand the usage ofApplicationContext and WebApplicationContext for complex scenarios. BothApplicationContext and WebApplicationContext extend the BeanFactory class and provides advanced configuration such as loading resourcespublishing events etc. So, there must be way for the Spring Bean to know which Bean Factory has actually loaded it. Here comes the BeanFactoryAware interface in which the method setBeanFactory()will be passed an instance of the Bean Factory object that configured and created this Bean.

package javabeat.net.articles.spring.lifecycle;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;public class BeanWithBeanFactoryAware implements BeanFactoryAware
{private BeanFactory beanFactory;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException{this.beanFactory = beanFactory;}public BeanFactory getBeanFactory(){return beanFactory;}
}

The following client code makes use of the above BeanWithBeanFactoryAware Bean. The Bean Factory object can either be an instance of BeanFactoryApplicationContext,WebApplicationContext, etc.

static void beanFactoryAwareTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");BeanFactory xmlBeanFactory = new XmlBeanFactory(resource);BeanWithBeanFactoryAware beanFactoryAwareBean =(BeanWithBeanFactoryAware)xmlBeanFactory.getBean("beanFactoryAwareBean");BeanFactory beanFactory = beanFactoryAwareBean.getBeanFactory();// Do something with this beanFactory object.
}

The following code is the Bean definition information for the above Bean which goes into the Configuration file.

<bean id="beanFactoryAwareBean" class="javabeat.net.articles.spring.lifecycle.BeanWithBeanFactoryAware">
</bean>

3.4) Bean Post Processor

Customization of Bean instances in an Application can happen for variety of reasons. For example, once a Bean object is created, various other data from a legacy system has to be populated on the Bean object. It may not be possible to configure the legacy data information in the Configuration file.

package javabeat.net.articles.spring.lifecycle;import java.util.List;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class DatabaseRow
{private String rowId;private int noOfColumns;private List values;public DatabaseRow(){}public String getRowId(){return rowId;}public void setRowId(String rowId){this.rowId = rowId;}public int getNoOfColumns(){return noOfColumns;}public void setNoOfColumns(int noOfColumns){this.noOfColumns = noOfColumns;}public List getValues(){return values;}public void setValues(List values){this.values = values;}
}

Let us consider a simple example for this. The above class represents a Database row and let us consider that even before the properties are set for this Bean object, the row-id and the number of columns in the row has to be populated. And once all the properties are set, then some other dependant properties also has to be set.
DBRowBeanPostProcessor.java

package javabeat.net.articles.spring.lifecycle;import java.util.Arrays;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class DBRowBeanPostProcessor implements BeanPostProcessor
{@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException{System.out.println("Before Initialization");System.out.println("Bean object: " + bean);System.out.println("Bean name: " + beanName);DatabaseRow dbRow = null;if (bean instanceof DatabaseRow){dbRow = (DatabaseRow)bean;dbRow.setRowId("ROWID-001");dbRow.setNoOfColumns(3);return dbRow;}return null;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException{System.out.println("After Initialization");System.out.println("Bean object: " + bean);System.out.println("Bean name: " + beanName);DatabaseRow dbRow = null;if (bean instanceof DatabaseRow){dbRow = (DatabaseRow)bean;dbRow.setValues(Arrays.asList("Antony", "10", "93232"));return dbRow;}return null;}
}

We have defined one Bean Post Processor class for customizing the behavior for some set of Beans with common nature. The method postProcessBeforeInitialization() will be called even before the properties for the Bean are set. And the methodpostProcessAfterInitialization() will be called after the properties for the Bean object are set.

static void beanPostProcessorTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");ConfigurableBeanFactory xmlBeanFactory = new XmlBeanFactory(resource);DBRowBeanPostProcessor processor = new DBRowBeanPostProcessor();xmlBeanFactory.addBeanPostProcessor(processor);DatabaseRow databaseRow =(DatabaseRow)xmlBeanFactory.getBean("databaseRow");System.out.println("Row Id: " + databaseRow.getRowId());System.out.println("Columns: " + databaseRow.getNoOfColumns());System.out.println("Values : " + databaseRow.getValues().toString());
}

The above client code registers the custom Bean Post Processor to the Bean Factory object by calling the method BeanFactory.addBeanPostProcessor(). It is possible to add any number of Bean Post Processor objects.

<bean id="databaseRow" class="javabeat.net.articles.spring.lifecycle.DatabaseRow">
</bean>

3.5) Initializing Bean

EmployeeBean.java

package javabeat.net.articles.spring.lifecycle;import org.springframework.beans.factory.InitializingBean;public class EmployeeBean implements InitializingBean
{private String name;private int age;private double salary;public EmployeeBean(){}public String getName(){return name;}public void setName(String name){this.name = name;}public int getAge(){return age;}public void setAge(int age){this.age = age;}public double getSalary(){return salary;}public void setSalary(double salary){this.salary = salary;}@Overridepublic void afterPropertiesSet() throws Exception{if (name == null || age == 0 || salary == 0.0d){throw new Exception("Mandatory field not set.");}}
}

The InitializingBean interface may be implemented by Bean class who wish to do some post processing actions when all the properties have been set. For example, the above sample code tries to check whether all the properties are set and if not and an exception is thrown.

static void initializingBeanTest()
{try{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");BeanFactory xmlBeanFactory = new XmlBeanFactory(resource);EmployeeBean johnson = (EmployeeBean)xmlBeanFactory.getBean("johnson");System.out.println("Name: " + johnson.getName());System.out.println("Age: " + johnson.getAge());System.out.println("Salary: " + johnson.getSalary());}catch (Exception exception){exception.printStackTrace();}
}

In the configuration file, we have purposely omitted the property 'name' which means that we an instance of the Bean object is created the name variable will be pointing to null, thereby throwing an exception in the afterPropertiesSet() method.

<bean id="johnson" class="javabeat.net.articles.spring.lifecycle.EmployeeBean">
<property name = "age" value = "43" />
<property name = "salary" value = "4834938.32" />
</bean>

3.6) Custom Init Method

CustomInitMethodBean.java

package javabeat.net.articles.spring.lifecycle;public class CustomInitMethodBean
{public void customInitMethod(){System.out.println("Custom init method called for this bean");}
}

One of the drawbacks with the InitializingBean interface is that the client code is dependant on Spring specific APIs. If you feel that approach is not fine, then you can define your own initialization method in your Spring class and configure the method in the Xml file.

static void customInitMethodTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");BeanFactory xmlBeanFactory = new XmlBeanFactory(resource);CustomInitMethodBean bean =(CustomInitMethodBean)xmlBeanFactory.getBean("customInitMethodBean");
}

For the above Bean class, we have defined a method called customInitMethod() and we have configured the same in the 'init-method' attribute. This means that the methodcustomInitMethod() will be called once all the properties for the Bean is set.

<bean id="customInitMethodBean" class="javabeat.net.articles.spring.lifecycle.CustomInitMethodBean"init-method = "customInitMethod">
</bean>

3.7) Disposable Bean

ConnectionManager.java

package javabeat.net.articles.spring.lifecycle;import java.util.ArrayList;
import java.util.List;import org.springframework.beans.factory.DisposableBean;public class ConnectionManager implements DisposableBean
{private List connections = new ArrayList();public ConnectionManager(){for (int i = 0; i < 5; i++){Connection connection = new Connection();connection.open();connections.add(connection);}}@Overridepublic void destroy() throws Exception{System.out.println("Closing all connections");for (Connection connection : connections){connection.close();}}class Connection{public void open() {}public void close() {}}
}

This interface is exactly the reverse of InitializingBean interface. The methoddestroy() in the DisposableBean will be called once the Bean reference is no longer needed by the Application code, or the Bean instance is forced to be removed through some APIs.

static void disposableBeanTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");ConfigurableListableBeanFactory xmlBeanFactory = new XmlBeanFactory(resource);ConnectionManager connectionManager =(ConnectionManager)xmlBeanFactory.getBean("myConnectionManager");xmlBeanFactory.destroySingletons();
}

The default scope for all the Beans is singleton, which means that only one instance is created irrespective of the number of calls made to BeanFactory.getBean("beanName"). In the above client code, we have called the method BeanFactory.destroySingletons()which will forcibly remove the Bean instance managed by the Bean Factory in which case the destroy method will be called.

<bean id="myConnectionManager" class="javabeat.net.articles.spring.lifecycle.ConnectionManager">
</bean>

3.8) Custom Destroy Method

CustomDestroyMethodBean.java

package javabeat.net.articles.spring.lifecycle;public class CustomDestroyMethodBean
{public void customDestroyMethod(){System.out.println("This method will be called upon bean destruction.");}
}

If we dont prefer a Spring Bean to depend on Spring specific API for destruction, then all we can do is to define a custom method in the implementation class and make appropriate configuration in the Xml file.

static void customDestroyMethodTest()
{Resource resource = new FileSystemResource("./src/resources/bean-lifecycle.xml");ConfigurableListableBeanFactory xmlBeanFactory = new XmlBeanFactory(resource);CustomDestroyMethodBean bean =(CustomDestroyMethodBean)xmlBeanFactory.getBean("customDestroyMethodBean");xmlBeanFactory.destroySingletons();
}

The method customDestroyMethod defined in the above Bean in configured through the means of the attribute 'destroy-method'.

<bean id="customDestroyMethodBean" class="javabeat.net.articles.spring.lifecycle.CustomDestroyMethodBean"destroy-method = "customDestroyMethod">
</bean>

4) Conclusion

In this article, we have discussed the contract between Spring Beans and the IOC Container. We have also listed down the series of steps that will be occurring at relevant intervals during the entire life cycle of Spring Beans.

附,另一张图片:http://i.stack.imgur.com/MArmL.png

转载于:https://www.cnblogs.com/davidwang456/p/5632832.html

spring bean生命周期管理--转相关推荐

  1. Spring框架:三种Spring Bean生命周期技术

    当使用术语"生命周期"时,Spring的家伙指的是您的bean的构造和破坏,通常这与Spring Context的构造和破坏有关. 在某些情况下,Bean生命周期的管理不是一件容易 ...

  2. 【一文读懂】Spring Bean生命周期详解

    Spring Bean的生命周期 1 容器初始化 BeanFactory容器初始化:包含容器创建,资源定位,载入,注册. ApplicationContext容器初始化:包含容器创建,资源定位,载入, ...

  3. Spring Bean生命周期:Bean的初始化阶段

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  4. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

  5. Spring Bean默认配置为单实例 Spring Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring 的Bean默认的是单例的. 如果不想单例需要如下配置: <bean id="user" ...

  6. Spring Bean生命周期: Bean的实例化

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  7. Spring Bean生命周期过程

    Spring Bean生命周期过程 Spring Bean生命周期指的是Bean加载Spring容器的过程,单例的Bean与多例的Bean加载过程是不一样的.这里指的是单例Bean的加载过程. 图:S ...

  8. Spring Bean 生命周期之“我从哪里来”?懂得这个很重要

    Spring bean 的生命周期很容易理解.实例化 bean 时,可能需要执行一些初始化以使其进入可用 (Ready for Use)状态.类似地,当不再需要 bean 并将其从容器中移除时,可能需 ...

  9. Spring5源码 - 06 Spring Bean 生命周期流程 概述 01

    文章目录 Bean生命周期概述 Demo finishBeanFactoryInitialization(beanFactory) 核心流程 Bean生命周期概述 说到Spring Bean的生命周期 ...

最新文章

  1. Linux下getsockopt/setsockopt 函数说明
  2. python获取文本光标_使用python readline时如何获取(并设置)当前bash光标位置?
  3. 使用Visual Studio 2008 进行远程调试
  4. [实变函数]4.2 Egrov 定理
  5. STM32F103中文参考手册之时钟树
  6. 计算机组装各个配件的选用,组装电脑各个配件装机心得与经验
  7. 【Win32汇编】五种寻址方式
  8. 纯文本邮件转为html,将纯文本电子邮件转换为HTML邮件
  9. 盈建科弹性板6计算_硅酸钙板的安装技巧和选购技巧
  10. LeetCode 713. 乘积小于K的子数组(滑动窗口)
  11. 收藏 | Python数据分析必备速查表
  12. C++11新特性(4)
  13. Linux 到 Windows scp 复制速度慢
  14. 过程改进的疑惑 - 习惯能改么?
  15. 微信小程序优惠券的购买和核销的操作流程设计
  16. MJKDZ PS2手柄控制OskarBot小车(二):硬件连接与通信时序
  17. 正在设定 ttf-mscorefonts-installer
  18. python正则表达式match方法_Python match()函数:匹配正则表达式
  19. 鸿蒙如何用JS开发智能手表App
  20. 对搜索引擎不友好的网站具有的特征

热门文章

  1. mysql中怎样扑抓到是那个字段出错_mysql 常见的几个错误问题
  2. java统计多个线程的请求次数_Web并发页面访问量统计实现
  3. lisp 任意点 曲线距离_奇怪的知识增加了:把标准形式的双曲线旋转来解决问题...
  4. python运用实例视频_python爬视频实例
  5. java定焦点_Android 开发 Camera1_如何使用对焦功能
  6. python中顺序查找法例子_Python查找算法(一)------ 顺序查找
  7. java sofa rpc_【剖析 | SOFARPC 框架】
  8. linux的json命令安装,linux 下强大的 JSON 解析命令 jq
  9. php 菜谱 源码,基于php的菜谱大全api调用代码实例
  10. 画面逐渐放大_日本80后画“人体妖女”,画面诡异,放大10倍越看越可怕