Spring 管理bean的生命周期

时间:2022-08-25 19:05:22
两个生命周期时间与bean关系尤为重要: 
postinitialization(初始化后)和predestruction(销毁前)。 

(Spring并不管理那些被配置成非单例bean的生命周期) 



指定初始化方法: 
view plaincopy to clipboardprint?
  1. package cn.partner4java.init;  
  2.   
  3. /** 
  4. * 指定初始化方法 
  5. * @author partner4java 
  6. * 
  7. */  
  8. public class SimpleBean {  
  9.     private String name;  
  10.     private int age = 0;  
  11.       
  12.     public void init(){  
  13.         if(name == null){  
  14.             System.out.println("name为空");  
  15.         }  
  16.         if(age == 0){  
  17.             System.out.println("age为0");  
  18.         }  
  19.     }  
  20.       
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.     public void setName(String name) {  
  25.         this.name = name;  
  26.     }  
  27.     public int getAge() {  
  28.         return age;  
  29.     }  
  30.     public void setAge(int age) {  
  31.         this.age = age;  
  32.     }  
  33.       
  34. }  
view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="  
  5.                 http://www.springframework.org/schema/beans  
  6.                 http://www.springframework.org/schema/beans/spring-beans.xsd">  
  7.                   
  8.     <bean id="simple1" class="cn.partner4java.init.SimpleBean"  
  9.             init-method="init">  
  10.         <property name="age" value="29"/>  
  11.         <property name="name" value="Dr. Jekyll"/>  
  12.     </bean>  
  13.     <bean id="simple2" class="cn.partner4java.init.SimpleBean"  
  14.             init-method="init">  
  15.         <property name="age" value="29"/>  
  16.     </bean>  
  17.     <bean id="simple3" class="cn.partner4java.init.SimpleBean"  
  18.             init-method="init">  
  19.         <property name="name" value="Mr. Hyde"/>  
  20.     </bean>  
  21.   
  22. </beans>  

调用:view plaincopy to clipboardprint?
  1.         //在调用获取的时候就会调用init,在调用init之前,已经使用控制反转设置方法依赖注入设置进数据  
  2.         BeanFactory beanFactory = getBeanFactory();  
  3.         System.out.println("simple1");  
  4.         beanFactory.getBean("simple1");  
  5.         System.out.println("simple2");  
  6.         beanFactory.getBean("simple2");  
  7.         System.out.println("simple3");  
  8.         beanFactory.getBean("simple3");  
  9.           
  10. //      后台打印:  
  11. //      simple1  
  12. //      simple2  
  13. //      name为空  
  14. //      simple3  
  15. //      age为0  




实现InitializingBean接口: 
Spring中InitializingBean接口允许你在bean的代码中这样定义:你希望bean能接收到Spring已经完成对其配置的通知。就像使用初始化方法时一样,你可以借机检查bean的配置以确保其有效,若要必要,还可以给出默认值。view plaincopy to clipboardprint?
  1. public class SimpleBeanIB implements InitializingBean {  
  2.     private static final String DEFAULT_NAME = "Jan Machacek";  
  3.     private String name;  
  4.     private int age = 0;  
  5.   
  6.     public String getName() {  
  7.         return name;  
  8.     }  
  9.   
  10.     public void setName(String name) {  
  11.         this.name = name;  
  12.     }  
  13.   
  14.     public int getAge() {  
  15.         return age;  
  16.     }  
  17.   
  18.     public void setAge(int age) {  
  19.         this.age = age;  
  20.     }  
  21.   
  22.     @Override  
  23.     public String toString() {  
  24.         final StringBuilder sb = new StringBuilder();  
  25.         sb.append("SimpleBean");  
  26.         sb.append("{name='").append(name).append('\'');  
  27.         sb.append(", age=").append(age);  
  28.         sb.append('}');  
  29.         return sb.toString();  
  30.     }  
  31.   
  32.     public void afterPropertiesSet() throws Exception {  
  33.         System.out.println("initializing bean");  
  34.         if (this.name == null) {  
  35.             System.out.println("No name specified, using default.");  
  36.             this.name = DEFAULT_NAME;  
  37.         }  
  38.         if (this.age == 0) {  
  39.             throw new IllegalArgumentException("You must set the [age] property bean of type [" + getClass().getName() + "]");  
  40.         }  
  41.     }  
  42. }  



决议顺序: 
Spring首先调用InitializingBean.afterPropertiesSet()方法,然后再调用初始化方法。(建议如果存在顺序,都写入到afterPropertiesSet中调用。) 


afterPropertiesSet方法和类的继承: 
例子抽象父类实现了接口,但是把afterPropertiesSet定义成了final,不可被子类覆盖,也就是去实现一些通用的初始化,然后再调用了自己定义的initSimple()初始化方法。 
父类:view plaincopy to clipboardprint?
  1. public abstract class SimpleBeanSupport implements InitializingBean {  
  2.     private String value;  
  3.   
  4.     /** 
  5.      * Subclasses may override this method to perform additional initialization. 
  6.      * This method gets invoked after the initialization of the {@link SimpleBeanSupport} 
  7.      * completes. 
  8.      * @throws Exception If the subclass initialization fails. 
  9.      */  
  10.     protected void initSimple() throws Exception {  
  11.         // do nothing  
  12.     }  
  13.   
  14.     public final void afterPropertiesSet() throws Exception {  
  15.         Assert.notNull(this.value, "The [value] property of [" + getClass().getName() + "] must be set.");  
  16.         initSimple();  
  17.     }  
  18.   
  19.     public final void setValue(String value) {  
  20.         this.value = value;  
  21.     }  
  22.   
  23.     protected final String getValue() {  
  24.         return this.value;  
  25.     }  
  26. }  

继承:view plaincopy to clipboardprint?
  1. public class SoutSimpleBean extends SimpleBeanSupport {  
  2.     private String person;  
  3.   
  4.     protected void initSimple() throws Exception {  
  5.         Assert.notNull(this.person, "The [person] property of [" + getClass().getName() + "] must be set.");  
  6.     }  
  7.   
  8.     public void setPerson(String person) {  
  9.         this.person = person;  
  10.     }  
  11.   
  12.     @Override  
  13.     public String toString() {  
  14.         return String.format("%s says \"%s\""this.person, getValue());  
  15.     }  
  16. }  

配置文件:view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="  
  5.                 http://www.springframework.org/schema/beans  
  6.                 http://www.springframework.org/schema/beans/spring-beans.xsd">  
  7.   
  8.     <bean id="simple1" class="com.apress.prospring2.ch04.lifecycle.SoutSimpleBean">  
  9.         <property name="person" value="Winston Churchill"/>  
  10.         <property name="value" value="This report, by its very length, defends itself against the risk of being read."/>  
  11.     </bean>  
  12.   
  13. </beans>  



嵌入bean的销毁: 
1、bean销毁时执行某一方法
view plaincopy to clipboardprint?
  1. public class DestructiveBean implements InitializingBean {  
  2.     private InputStream is = null;  
  3.     private String filePath = null;  
  4.   
  5.     public void afterPropertiesSet() throws Exception {  
  6.         System.out.println("Initializing Bean");  
  7.   
  8.         Assert.notNull(this.filePath, "The [filePath] property of [" + getClass().getName() + "] must be set.");  
  9.   
  10.         new File(this.filePath).createNewFile();  
  11.         this.is = new FileInputStream(this.filePath);  
  12.     }  
  13.   
  14.     public void destroy() {  
  15.         System.out.println("Destroying Bean");  
  16.   
  17.         if (this.is != null) {  
  18.             try {  
  19.                 this.is.close();  
  20.                 this.is = null;  
  21.                 new File(this.filePath).delete();  
  22.             } catch (IOException ex) {  
  23.                 System.err.println("WARN: An IOException occured"  
  24.                         + " while trying to close the InputStream");  
  25.             }  
  26.         }  
  27.     }  
  28.   
  29.     public void setFilePath(String filePath) {  
  30.         this.filePath = filePath;  
  31.     }  
  32.   
  33.     @Override  
  34.     public String toString() {  
  35.         final StringBuilder sb = new StringBuilder();  
  36.         sb.append("DestructiveBean");  
  37.         sb.append("{is=").append(is);  
  38.         sb.append(", filePath='").append(filePath).append('\'');  
  39.         sb.append('}');  
  40.         return sb.toString();  
  41.     }  
  42. }  

配置文件:view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="  
  5.                 http://www.springframework.org/schema/beans  
  6.                 http://www.springframework.org/schema/beans/spring-beans.xsd">  
  7.   
  8.     <bean id="destructive" class="com.apress.prospring2.ch04.lifecycle.DestructiveBean"  
  9.             destroy-method="destroy">  
  10.         <property name="filePath" value="/tmp/prospring25"/>  
  11.     </bean>  
  12.   
  13. </beans>  

2、实现DisposableBean接口 
DisposableBean接口提供了destory方法。view plaincopy to clipboardprint?
  1. public class DestructiveBeanI implements InitializingBean, DisposableBean {  
  2.     private InputStream is = null;  
  3.     private String filePath = null;  
  4.   
  5.     public void afterPropertiesSet() throws Exception {  
  6.         System.out.println("Initializing Bean");  
  7.   
  8.         Assert.notNull(this.filePath, "The [filePath] property of [" + getClass().getName() + "] must be set.");  
  9.   
  10.         new File(this.filePath).createNewFile();  
  11.         this.is = new FileInputStream(this.filePath);  
  12.     }  
  13.   
  14.     public void destroy() {  
  15.         System.out.println("Destroying Bean");  
  16.   
  17.         if (this.is != null) {  
  18.             try {  
  19.                 this.is.close();  
  20.                 this.is = null;  
  21.                 new File(this.filePath).delete();  
  22.             } catch (IOException ex) {  
  23.                 System.err.println("WARN: An IOException occured"  
  24.                         + " while trying to close the InputStream");  
  25.             }  
  26.         }  
  27.     }  
  28.   
  29.     public void setFilePath(String filePath) {  
  30.         this.filePath = filePath;  
  31.     }  
  32.   
  33.     @Override  
  34.     public String toString() {  
  35.         final StringBuilder sb = new StringBuilder();  
  36.         sb.append("DestructiveBean");  
  37.         sb.append("{is=").append(is);  
  38.         sb.append(", filePath='").append(filePath).append('\'');  
  39.         sb.append('}');  
  40.         return sb.toString();  
  41.     }  
  42. }  

配置文件:view plaincopy to clipboardprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="  
  5.                 http://www.springframework.org/schema/beans  
  6.                 http://www.springframework.org/schema/beans/spring-beans.xsd">  
  7.   
  8.     <bean id="destructive" class="com.apress.prospring2.ch04.lifecycle.DestructiveBeanI">  
  9.         <property name="filePath" value="/tmp/prospring25"/>  
  10.     </bean>  
  11.   
  12. </beans>  

3、使用关闭钩子 
注入关闭代码:view plaincopy to clipboardprint?
  1. public class ShutdownHook implements Runnable {  
  2.     private ConfigurableListableBeanFactory beanFactory;  
  3.   
  4.     public ShutdownHook(ConfigurableListableBeanFactory beanFactory) {  
  5.         Assert.notNull(beanFactory, "The 'beanFactory' argument must not be null.");  
  6.         this.beanFactory = beanFactory;  
  7.     }  
  8.   
  9.     public void run() {  
  10.         this.beanFactory.destroySingletons();  
  11.     }  
  12. }  

调用代码:view plaincopy to clipboardprint?
  1. public class ShutdownHookDemo {  
  2.   
  3.     public static void main(String[] args) throws IOException {  
  4.         XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("/META-INF/spring/lifecycledemo5-context.xml"));  
  5.         Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(factory)));  
  6.         new BufferedInputStream(System.in).read();  
  7.     }  
  8.   
  9. }