Spring框架的Bean的初始化分爲以下幾種
談bean必然要談生命週期
Bean的生命週期
通常意義上講的bean的名稱週期,指的是bean從創建到初始化,經過一系列的流程,最終銷燬的過程。只不過,在Spring中,bean的生命週期是由Spring容器來管理的。在Spring中,我們可以自己來指定bean的初始化和銷燬的方法。當我們指定了bean的初始化和銷
如何定義初始化和銷燬方法?
我們已經知道了由Spring管理bean的生命週期時,我們可以指定bean的初始化和銷燬方法,那具體該如何定義這些初始化和銷燬方法呢?接下來,我們就介紹第一種定義初始化和銷燬方法的方式:通過@Bean註解指定初始化和銷燬方法。
如果是使用XML文件的方式配置bean的話,可以在標籤中指定bean的初始化和銷燬方法,如下所示。
<bean id = "person" class="io.mykit.spring.plugins.register.bean.Person" init-method="init" destroy-method="destroy">
<property name="name" value="binghe"></property>
<property name="age" value="18"></property>
</bean>
這裏,需要注意的是,在我們寫的Person類中,需要存在init()方法和destroy()方法。而且Spring中規定,這裏的init()方法和destroy()方法必須是無參方法,但可以拋異常。
如果我們使用註解的方式,該如何實現指定bean的初始化和銷燬方法呢?接下來,我們就一起來搞定它!!
首先,創建一個名稱爲Student的類,這個類的實現比較簡單,如下所示。銷毀方法時,當容器在bean進行到當前生命週期的階段時,會自動調用我們自定義的初始化和銷燬方法。
package io.mykit.spring.plugins.register.bean; public class Student { public Student(){ System.out.println("Student類的構造方法"); } public void init(){ System.out.println("初始化Student對象"); } public void destroy(){ System.out.println("銷燬Student對象"); } }
接下來,我們將Student類對象通過註解的方式註冊到Spring容器中,具體的做法就是新建一個LifeCircleConfig類作爲Spring的配置類,將Student類對象通過LifeCircleConfig類註冊到Spring容器中,LifeCircleConfig類的代碼如下所示。
import io.mykit.spring.plugins.register.bean.Student; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class LifeCircleConfig { @Bean public Student student(){ return new Student(); } }
接下來,我們就新建一個BeanLifeCircleTest類來測試容器中的Student對象,BeanLifeCircleTest類的部分代碼如下所示。
public class BeanLifeCircleTest { @Test public void testBeanLifeCircle01(){ //創建IOC容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCircleConfig.class); System.out.println("容器創建完成..."); } }
對於單實例bean對象來說,在Spring容器創建完成後,就會對單實例bean進行實例化。那麼,我們先來運行下BeanLifeCircleTest類中的testBeanLifeCircle01()方法,輸出的結果信息如下所示。
(在不做特殊化的前提下即spring框架創建普通對象(bean) 就只會構建構建當前對象構造方法)
Student類的構造方法
容器創建完成...
可以看到,在Spring容器創建完成時,自動調用單實例bean的構造方法,對單實例bean進行了實例化操作。
總之:對於單實例bean來說,在Spring容器啓動的時候創建對象;對於多實例bean來說,在每次獲取bean的時候創建對象。
<bean id="student" class="io.mykit.spring.plugins.register.bean.Student" init-method="init" destroy-method="destroy"></bean>
如果我們在@Bean註解中該如何實現呢?其實就更簡單了,我們來看下@Bean註解的源碼,如下所示。
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.core.annotation.AliasFor; @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Bean { @AliasFor("name") String[] value() default {}; @AliasFor("value") String[] name() default {}; @Deprecated Autowire autowire() default Autowire.NO; boolean autowireCandidate() default true; String initMethod() default ""; String destroyMethod() default AbstractBeanDefinition.INFER_METHOD; }
看到@Bean註解的源碼,相信小夥伴們會有種豁然開朗的感覺:沒錯,就是使用@Bean註解的initMethod屬性和destroyMethod屬性來指定bean的初始化方法和銷燬方法。
所以,我們在LifeCircleConfig類中的@Bean註解中指定initMethod屬性和destroyMethod屬性,如下所示。
@Bean(initMethod = "init", destroyMethod = "destroy") public Student student(){ return new Student(); }
此時,我們再來運行BeanLifeCircleTest類中的testBeanLifeCircle01()方法,輸出的結果信息如下所示。
Student類的構造方法
初始化Student對象
容器創建完成...
從輸出結果可以看出,在Spring容器中,先是調用了Student類的構造方法來創建Student對象,接下來調用了Student對象的init()方法來進行初始化。
那小夥伴們可能會問,運行上面的代碼沒有打印出bean的銷燬方法中的信息啊,那什麼時候執行bean的銷燬方法呢? 這個問題問的很好, bean的銷燬方法是在容器關閉的時候調用的。
接下來,我們在BeanLifeCircleTest類中的testBeanLifeCircle01()方法中,添加關閉容器的代碼,如下所示。(context.close() 這個方法代表着容器的銷燬)
@Test public void testBeanLifeCircle01(){ //創建IOC容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCircleConfig.class); System.out.println("容器創建完成..."); context.close(); }
我們再來運行BeanLifeCircleTest類中的testBeanLifeCircle01()方法,輸出的結果信息如下所示。
Student類的構造方法
初始化Student對象
容器創建完成...
銷燬Student對象
可以看到,此時輸出了對象的銷燬方法中的信息,說明執行了對象的銷燬方法。
指定初始化和銷燬方法的使用場景
一個典型的使用場景就是對於數據源的管理。例如,在配置數據源時,在初始化的時候,對很多的數據源的屬性進行賦值操作;在銷燬的時候,我們需要對數據源的連接等信息進行關閉和清理。此時,我們就可以在自定義的初始化和銷燬方法中來做這些事情!
初始化和銷燬方法調用的時機
-
bean對象的初始化方法調用的時機:對象創建完成,如果對象中存在一些屬性,並且這些屬性也都賦值好之後,會調用bean的初始化方法。對於單實例bean來說,在Spring容器創建完成後,Spring容器會自動調用bean的初始化和銷燬方法;對於單實例bean來說,在每次獲取bean對象的時候,調用bean的初始化和銷燬方法。
-
bean對象的銷燬方法調用的時機:對於單實例bean來說,在容器關閉的時候,會調用bean的銷燬方法;對於多實例bean來說,Spring容器不會管理這個bean,也不會自動調用這個bean的銷燬方法。不過,小夥伴們可以手動調用多實例bean的銷燬方法。
@Scope("prototype") @Bean(initMethod = "init", destroyMethod = "destroy") public Student student(){ return new Student(); }
接下來,我們再來運行BeanLifeCircleTest類中的testBeanLifeCircle01()方法,輸出的結果信息如下所示。
容器創建完成...
可以看到,當我們將Student對象設置成多實例bean,並且沒有獲取bean實例對象時,Spring容器並沒有執行bean的構造方法、初始化方法和銷燬方法。
說到這,我們就在BeanLifeCircleTest類中的testBeanLifeCircle01()方法中添加一行獲取Student對象的代碼,如下所示。
@Test public void testBeanLifeCircle01(){ //創建IOC容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCircleConfig.class); System.out.println("容器創建完成..."); context.getBean(Student.class); context.close(); }
此時,我們再來運行BeanLifeCircleTest類中的testBeanLifeCircle01()方法,輸出的結果信息如下所示。
容器創建完成...
Student類的構造方法
初始化Student對象
這是因爲 將bean設置成多實例時,Spring不會自動調用bean對象的銷燬方法。至於多實例bean對象何時銷燬,那就是程序員自己的事情了!!Spring容器不再管理多實例bean。