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.
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 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;@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?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
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生命周期管理--转的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java.lang.Long canno
- 下一篇: spring 源码分析之BeanPost