鄭州網(wǎng)站建設(shè)饣漢獅網(wǎng)絡(luò)千鋒教育北京校區(qū)
目錄
一:Bean的生命周期
1.?什么是Bean的生命周期
2.?Bean的生命周期之5步
3.?Bean生命周期之7步
4.?Bean生命周期之10步
5.?Bean的scop(作用域)不同,管理方式不同
6.?自己new的對象如何讓Spring管理
一:Bean的生命周期
1.?什么是Bean的生命周期
(1)Spring其實(shí)就是一個管理Bean對象的工廠,它負(fù)責(zé)對象的創(chuàng)建,對象的銷毀等。
(2)所謂的生命周期就是:對象從創(chuàng)建開始到最終銷毀的整個過程。
(3)為什么要知道Bean的生命周期?
其實(shí)生命周期的本質(zhì)是:在哪個時間節(jié)點(diǎn)上調(diào)用了哪個類的哪個方法?我們需要充分的了解在這個生命線上,都有哪些特殊的時間節(jié)點(diǎn)!只有我們知道了特殊的時間節(jié)點(diǎn)都在哪,到時我們才可以確定代碼寫到哪。我們可能需要在某個特殊的時間點(diǎn)上執(zhí)行一段特定的代碼,這段代碼就可以放到這個節(jié)點(diǎn)上;當(dāng)生命線走到這里的時候,自然會被調(diào)用。
(4)下面我會按照由淺入深,按照5步、7步、10步法,講解Bean的生命周期!
2.?Bean的生命周期之5步
(1)Bean生命周期的管理,可以參考Spring的源碼:AbstractAutowireCapableBeanFactory類的doCreateBean()方法。
(2)Bean生命周期可以粗略的劃分為五大步:
- 第一步:實(shí)例化Bean
- 第二步:Bean屬性賦值
- 第三步:初始化Bean
- 第四步:使用Bean
- 第五步:銷毀Bean
編寫測試程序:
定義一個Bean
Bean的生命周期按照粗略的五步的話:
第一步:實(shí)例化Bean(調(diào)用無參數(shù)構(gòu)造方法)
第二步:給Bean屬性賦值(調(diào)用set方法)
第三步:初始化Bean(會調(diào)用Bean的init方法。注意:這個init方法需要自己寫)
第四步:使用Bean
第五步:銷毀Bean(會調(diào)用Bean的destroy方法。注意:這個destroy方法需要自己寫)
package com.bjpowernode.spring.bean;public class User {private String username;public void setUsername(String username) {System.out.println("第二步:給對象的屬性賦值");this.username = username;}public User() {System.out.println("第一步:實(shí)例化Bean,無參數(shù)構(gòu)造方法執(zhí)行了");}// 初始化Bean,需要自己寫,自己配,方法名隨意public void initBean(){System.out.println("第三步:初始化Bean");}// 銷毀Bean,需要自己寫,自己配,方法名隨意public void destroyBean(){System.out.println("第五步:銷毀Bean");}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +'}';}
}
spring.xml配置
需要在<bean>標(biāo)簽中調(diào)用init-method和destroy-method屬性,手動指定初始化方法和銷毀方法!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.bjpowernode.spring.bean.User"init-method="initBean" destroy-method="destroyBean"><!--給屬性賦值--><property name="username" value="張三"/></bean>
</beans>
?測試程序
①需要手動關(guān)閉Spring容器(調(diào)用close方法),這樣Spring容器才會銷毀Bean,才會去調(diào)用我們定義的destroyBean方法!
②?注意:只有ApplicationContext的實(shí)現(xiàn)類ClassPathXmlApplicationContext有close方法,ApplicationContext沒有,所以需要強(qiáng)制類型轉(zhuǎn)換;然后調(diào)用close方法!
package com.bjpowernode.spring.test;import com.bjpowernode.spring.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class BeanLifecycleTest {@Testpublic void testBeanLifeCycleFive(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");User user = applicationContext.getBean("user", User.class);System.out.println("第四步:使用Bean"+user);// 需要手動關(guān)閉Spring容器ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;context.close();}
}
執(zhí)行結(jié)果:從這里我們也可看出執(zhí)行的順序
總結(jié)要點(diǎn):
第一:只有正常關(guān)閉spring容器(調(diào)用close方法),bean的銷毀方法才會被調(diào)用。
第二:ClassPathXmlApplicationContext類才有close()方法。
第三:配置文件中的init-method指定初始化方法,destroy-method指定銷毀方法。
3.?Bean生命周期之7步
(1)在以上的5步中,第3步是初始化Bean,如果你還想在初始化前和初始化后添加代碼,可以加入“Bean后處理器”;需要編寫一個類實(shí)現(xiàn)BeanPostproccessor接口,并重寫里面的befor和after方法。
(2)Bean生命周期可以細(xì)化為七大步:
- 第一步:實(shí)例化Bean
- 第二步:Bean屬性賦值
- 第三步:執(zhí)行“Bean后處理器”的before方法
- 第四步:初始化Bean
- 第五步:執(zhí)行“Bean后處理器”的after方法
- 第六步:使用Bean
- 第七步:銷毀Bean
編寫一個類實(shí)現(xiàn)BeanPostProcessor類,并且重寫before和after方法
注意:方法中有兩個參數(shù):
①第一個參數(shù)是創(chuàng)建的Bean對象!
②第二個參數(shù)是Bean的名字!
package com.bjpowernode.spring.test;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class LogBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean后處理器的before方法執(zhí)行,即將開始初始化");return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("Bean后處理器的after方法執(zhí)行,已完成初始化");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
在spring.xml文件中配置“Bean后處理器”
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.bjpowernode.spring.bean.User"init-method="initBean" destroy-method="destroyBean"><!--給屬性賦值--><property name="username" value="張三"/></bean><!--配置Bean后處理器。這個后處理器將作用于當(dāng)前配置文件中所有的bean。--><bean class="com.bjpowernode.spring.bean.LogBeanPostProcessor"/>
</beans>
執(zhí)行測試程序:
?一定要注意:在spring.xml文件中配置的Bean后處理器將作用于當(dāng)前配置文件中所有的Bean!
4.?Bean生命周期之10步
Bean生命周期十步:比七步添加的那三步在哪里?
(1)在“Bean后處理器”before方法之前干了什么事兒?
檢查Bean是否實(shí)現(xiàn)了Aware相關(guān)的接口,如果實(shí)現(xiàn)了接口則調(diào)用這些接口中的方法;調(diào)用這些方法的目的是為了給你傳遞一些數(shù)據(jù),讓你更加方便使用。(2)在“Bean后處理器”before方法之后干了什么事兒?
檢查Bean是否實(shí)現(xiàn)了InitializingBean接口,如果實(shí)現(xiàn)了,則調(diào)用接口中的方法。(3)使用Bean之后,或者說銷毀Bean之前干了什么事兒?
檢查Bean是否實(shí)現(xiàn)了DisposableBean接口,如果實(shí)現(xiàn)了,則調(diào)用接口中的方法。總結(jié):添加的這三個點(diǎn)位的特點(diǎn),都是在檢查你這個Bean是否實(shí)現(xiàn)了某些特定的接口,如果實(shí)現(xiàn)了這些接口,則Spring容器會調(diào)用這個接口中的方法!
Aware相關(guān)的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
①當(dāng)Bean實(shí)現(xiàn)了BeanNameAware,Spring會將Bean的名字傳遞給Bean。
②當(dāng)Bean實(shí)現(xiàn)了BeanClassLoaderAware,Spring會將加載該Bean的類加載器傳遞給Bean。
③當(dāng)Bean實(shí)現(xiàn)了BeanFactoryAware,Spring會將Bean工廠對象傳遞給Bean。
測試以上10步,可以讓User類實(shí)現(xiàn)5個接口,并實(shí)現(xiàn)所有方法:
①BeanNameAware
②BeanClassLoaderAware
③BeanFactoryAware
④InitializingBean
⑤DisposableBean
User類
package com.bjpowernode.spring.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;public class User implementsBeanNameAware, BeanClassLoaderAware, BeanFactoryAware,InitializingBean, DisposableBean{private String username;public void setUsername(String username) {System.out.println("第二步:給對象的屬性賦值");this.username = username;}public User() {System.out.println("第一步:實(shí)例化Bean,無參數(shù)構(gòu)造方法執(zhí)行了");}// 初始化Bean,需要自己寫,自己配,方法名隨意public void initBean(){System.out.println("第四步:初始化Bean");}// 銷毀Bean,需要自己寫,自己配,方法名隨意public void destroyBean(){System.out.println("第七步:銷毀Bean");}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +'}';}@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("類加載器:" + classLoader);}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("Bean工廠:" + beanFactory);}@Overridepublic void setBeanName(String name) {System.out.println("Bean的名字:" + name);}@Overridepublic void destroy() throws Exception {System.out.println("DisposableBean destroy方法執(zhí)行了");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("InitializingBean afterPropertiesSet方法執(zhí)行了");}
}
執(zhí)行結(jié)果:
總結(jié):
①InitializingBean的方法早于init-method的執(zhí)行。
②DisposableBean的方法早于destroy-method的執(zhí)行。
5.?Bean的scop(作用域)不同,管理方式不同
Spring 根據(jù)Bean的作用域來選擇管理方式!
(1)對于singleton(單例)作用域的Bean,Spring 能夠精確地知道該Bean何時被創(chuàng)建,何時初始化完成,以及何時被銷毀。
(2)而對于 prototype(多例/原型) 作用域的 Bean,Spring 只負(fù)責(zé)創(chuàng)建,當(dāng)容器創(chuàng)建了 Bean 的實(shí)例后,Bean 的實(shí)例就交給客戶端代碼管理,Spring 容器將不再跟蹤其生命周期。
把spring.xml配置文件當(dāng)中scop屬性的singleton改成property
再次執(zhí)行測試程序:
實(shí)際上只有前8步了,對于后兩步的:檢查Bean是否實(shí)現(xiàn)了DisposableBean接口 和 銷毀Bean就不管了!
6.?自己new的對象如何讓Spring管理
有些時候可能會遇到這樣的需求,某個java對象是我們自己手動new的,然后我們希望這個對象被Spring容器管理,怎么實(shí)現(xiàn)呢?
Student類
package com.bjpowernode.spring.bean;public class Student {
}
進(jìn)行測試:
第一步:創(chuàng)建DefaultListableBeanFactory對象!
第二步:注冊Bean,調(diào)用這個對象的registerSingleton方法,把自己創(chuàng)建的對象傳進(jìn)去,并起一個名字!
第三步:根據(jù)名字,調(diào)用getBean方法從Spring容器當(dāng)中獲取Bean對象!
package com.bjpowernode.spring.test;import com.bjpowernode.spring.bean.Student;
import com.bjpowernode.spring.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class BeanLifecycleTest {@Testpublic void testBeanRegister(){// 自己new的對象,沒有被Spring管理Student student = new Student();System.out.println(student);// 創(chuàng)建DefaultListableBeanFactory對象DefaultListableBeanFactory factory = new DefaultListableBeanFactory();// 調(diào)用registerSingleton方法注冊Beanfactory.registerSingleton("studentBean",student);// 從Spring容器當(dāng)中取出BeanStudent studentBean = factory.getBean("studentBean", Student.class);System.out.println(studentBean);}
}
執(zhí)行結(jié)果:
獲取到的是同一個Bean對象,說明確實(shí)是把我們創(chuàng)建的對象放到Spring容器當(dāng)中進(jìn)行管理!