spring bean生命周期管理--转
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
A 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.
- The Bean Container finds the definition of the Spring Bean in the Configuration file.
- The Bean Container creates an instance of the Bean using Java Reflection API.
- If any properties are mentioned, then they are also applied. If the property itself is a Bean, then it is resolved and set.
- If the Bean class implements the
BeanNameAwareinterface, then thesetBeanName()method will be called by passing the name of the Bean. - If the Bean class implements the
BeanClassLoaderAwareinterface, then the methodsetBeanClassLoader()method will be called by passing an instance of theClassLoaderobject that loaded this bean. - If the Bean class implements the
BeanFactoryAwareinterface, then the methodsetBeanFactory()will be called by passing an instance ofBeanFactoryobject. - If there are any
BeanPostProcessorsobject associated with theBeanFactorythat loaded the Bean, then the methodpostProcessBeforeInitialization()will be called even before the properties for the Bean are set. - If the Bean class implements the
InitializingBeaninterface, then the methodafterPropertiesSet()will be called once all the Bean properties defined in the Configuration file are set. - 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. - The
postProcessAfterInitialization()method will be called if there are any Bean Post Processors attached for the Bean Factory object. - If the Bean class implements the
DisposableBeaninterface, then the methoddestroy()will be called when the Application no longer needs the bean reference. - 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;
} @Override
public 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; @Override
public 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 resources, publishing 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; @Override
public 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 BeanFactory, ApplicationContext,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
{ @Override
public 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;
} @Override
public 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;
} @Override
public 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);
}
} @Override
public 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

spring bean生命周期管理--转的更多相关文章
- 大厂高频面试题Spring Bean生命周期最详解
Spring作为当前Java最流行.最强大的轻量级框架.Spring Bean的生命周期也是面试高频题,了解Spring Bean周期也能更好地帮助我们解决日常开发中的问题.程序员应该都知道Sprin ...
- Spring Bean生命周期,好像人的一生。。
大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...
- spring bean 生命周期和 ? 作用域? spirng bean 相互依赖? jvm oom ? jvm 监控工具? ThreadLocal 原理
1. spring bean 生命周期 1. 实例化一个bean ,即new 2. 初始化bean 的属性 3. 如果实现接口 BeanNameAware ,调用 setBeanName 4. Bea ...
- Spring点滴四:Spring Bean生命周期
Spring Bean 生命周期示意图: 了解Spring的生命周期非常重要,我们可以利用Spring机制来定制Bean的实例化过程. -------------------------------- ...
- Spring Bean 生命周期之destroy——终极信仰
上一篇文章 Spring Bean 生命周期之我从哪里来 说明了我是谁? 和 我从哪里来? 的两大哲学问题,今天我们要讨论一下终极哲学我要到哪里去? 初始化 Spring Bean 有三种方式: @P ...
- 常见问题:Web/Servlet生命周期与Spring Bean生命周期
Servlet生命周期 init()初始化阶段 Servlet容器加载Servlet(web.xml中有load-on-startup=1;Servlet容器启动后用户首次向Servlet发请求;Se ...
- 睡前聊一聊"spring bean 生命周期"
spring bean 生命周期=实属初销+2个常见接口+3个Aware型接口+2个生命周期接口 实属初销:spring bean生命周期只有四个阶段,即实例化->属性赋值->初始化-&g ...
- 【不懂】spring bean生命周期
完整的生命周期(牢记): 1.spring容器准备 2.实例化bean 3.注入依赖关系 4.初始化bean 5.使用bean 6.销毁bean Bean的完整生命週期可以認為是從容器建立初始化Bea ...
- Spring Bean 生命周期2
在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Sin ...
随机推荐
- ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
一.前言 大家都知道,在之前,我们Asp.net 的网站都只能部署在IIS上,并且IIS也只存在于Windows上,这样Asp.net开发的网站就难以做到跨平台.由于微软的各项技术的开源,所以微软自然 ...
- Java多线程10:ThreadLocal的作用及使用
ThreadLocal的作用 从上一篇对于ThreadLocal的分析来看,可以得出结论:ThreadLocal不是用来解决共享对象的多线程访问问题的,通过ThreadLocal的set()方法设置到 ...
- Java多线程9:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
- Dojo动画原理解析
dojo中动画部分分为两部分:dojo/_base/fx, dojo/fx.dojo/_base/fx部分是dojo动画的基石,里面有两个底层API:animateProperty.anim和两个常用 ...
- 【源码笔记】Nop定时任务
网站需要定时执行不同的任务,比如清理无效的数据.定时发送mail等,Nop的这个定时任务设计比较好,简单的说就是将所有任务相同的属性持久化,具体的执行通过继承接口来实现. 持久化对象:Schedule ...
- IE浏览器不能自动显示PDF文件的解决办法
今天更新了Adobe的PDF Reader,更新后发现在网页上无法预览PDF文件了,点击PDF的连接,浏览器就会提示下载或者打开,感觉很不爽,经过一番百度,找到了解决办法,在这里分享一下. 打开IE浏 ...
- 曲演杂坛--特殊字符/生僻字与varchar
对于中文版的SQL SERVER,默认安装后使用的默认排序规则为Chinese_PRC_CI_AS,在此排序规则下,使用varchar类型来可以“正常存取”存放中文字符以及一些东南亚国家的字符,同时v ...
- jQuery实现在线文档
1.1.1 摘要 现在,许多网站都提供在线图片和图书阅读的功能,这种方式比下载后阅读来的直观和人性化,要实现该功能涉及到点击处理和图片动态加载. 在接下来的博文中,我们将通过Javascript方式实 ...
- 简单JavaScript模版引擎优化
在上篇博客最简单的JavaScript模板引擎 说了一下一个最简单的JavaScript模版引擎的原理与实现,作出了一个简陋的版本,今天优化一下,使之能够胜任日常拼接html工作,先把上次写的模版函数 ...
- java arraylist的问题
不得不说,我犯了错,很基础的.. 遍历list的时候可以删除数组元素吗? 答案是:简单/增强for循环不可以,list.iterator()这样的方式就可以. 我之前做过类似面试题的,不过忘记了, 不 ...