IOC的概念
- IOC Inversion of Controller 控制反轉(zhuǎn)。
- IOC 就是將對(duì)象的創(chuàng)建皿渗、初始化及銷毀交給 spring 容器來(lái)處理成榜。
ApplicationContext 與 BeanFactory 的關(guān)系
- ApplicationContext 是 BeanFactory 的子接口规求。
- BeanFactory 采用延遲加載的方案,在getBean時(shí)才會(huì)實(shí)例化Bean幽钢。
- XmlBeanFactory
public void test4() { BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); beanFactory.getBean("helloWorld"); } // 經(jīng)過(guò)測(cè)試,BeanFactory在getBean時(shí)才實(shí)例化Bean傅是。
- ApplicationContext 在配置文件加載時(shí)匪燕,就會(huì)初始化Bean蕾羊,并且提供不同應(yīng)用層的實(shí)現(xiàn)。在開(kāi)發(fā)中我們一般使用 ApplicationContext 的實(shí)現(xiàn)類:
- FileSystemXmlApplicationContext 根據(jù)文件路徑讀取xml文件
public void test5() { // 根據(jù)系統(tǒng)文件路徑讀取xml文件 ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml"); context.getBean("helloWorld"); }
- ClassPathXmlApplicationContext 根據(jù)classpath路徑讀取xml文件
public void test5() { // 根據(jù)classpath路徑讀取xml文件 ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml"); context.getBean("helloWorld"); }
- WebApplicationContext web開(kāi)發(fā)中常用
Bean的實(shí)例化方式
- 無(wú)參構(gòu)造方法
- 編寫(xiě)配置文件
applicationContext.xml
<?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="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/> </beans>
- 編寫(xiě)測(cè)試方法
public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.show(); }
- 編寫(xiě)配置文件
- 靜態(tài)工廠方法
- 編寫(xiě)工廠類帽驯,在工廠類中提供一個(gè)靜態(tài)方法龟再,返回Bean對(duì)象
public class HelloWorldFactory { public static HelloWorld getInstance() { return new HelloWorld(); } }
- 編寫(xiě)配置文件
applicationContext.xml
<?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="helloWorld2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory" factory-method="getInstance"/> </beans>
- 編寫(xiě)測(cè)試方法
public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld2"); helloWorld.show(); }
- 實(shí)例工廠方法
- 編寫(xiě)工廠類,在工廠類中提供一個(gè)非靜態(tài)方法尼变,返回Bean對(duì)象
public class HelloWorldFactory2 { public HelloWorld getInstance() { return new HelloWorld(); } }
- 編寫(xiě)配置文件
applicationContext.xml
<?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="helloWorldFactory2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory2"/> <bean id="helloWorld3" factory-bean="helloWorldFactory2" factory-method="getInstance"/> </beans>
- 編寫(xiě)測(cè)試方法
public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3"); helloWorld.show(); }
Bean的別名
- 編寫(xiě)配置文件
<?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="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
<alias name="helloWorld" alias="a"/>
<alias name="helloWorld" alias="b"/>
<alias name="helloWorld" alias="c"/>
</beans>
- 編寫(xiě)測(cè)試方法
public void testAlias() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld a = (HelloWorld) context.getBean("a");
a.show();
HelloWorld b = (HelloWorld) context.getBean("b");
b.show();
HelloWorld c = (HelloWorld) context.getBean("c");
c.show();
}
Bean的創(chuàng)建時(shí)機(jī)
- 在 bean 標(biāo)簽中有 lazy-init 屬性
- default利凑,相當(dāng)于 false,在 spring 容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象嫌术。
- true哀澈,在 context.getBean 時(shí)創(chuàng)建對(duì)象。
- false度气,在 spring 容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象割按。
- lazy-init 屬性的意義
- 如果把 lazy-init 設(shè)置為 true ,則當(dāng) spring 容器啟動(dòng)的時(shí)候磷籍,檢測(cè)不到任何錯(cuò)誤适荣,這樣會(huì)存在很大的安全性隱患。所以一般情況應(yīng)該設(shè)置 lazy-init 為 false/default 院领。
- 但是如果一個(gè)bean中有一個(gè)屬性束凑,該屬性含有大量的數(shù)據(jù),這個(gè)時(shí)候不希望該bean過(guò)早的停留在內(nèi)存中栅盲,這個(gè)時(shí)候需要用到 lazy-int 為 true 汪诉。
Bean的作用域
- 在 bean 標(biāo)簽中有 scope 屬性,用于描述 bean 的作用域谈秫。
- singleton扒寄,單例模式,代表在 spring ioc 容器中只有一個(gè) bean 實(shí)例拟烫。(默認(rèn)的scope)
- prototype该编,多例模式,每一次從 spring ioc 容器中獲取硕淑,都會(huì)返回一個(gè)新實(shí)例课竣。
- request,用在web開(kāi)發(fā)中置媳,通過(guò) request.setAttribute() 將 bean 對(duì)象存儲(chǔ)到request域中于樟。
- session,用在web開(kāi)發(fā)中拇囊,通過(guò) session.setAttribute() 將 Bean 對(duì)象存儲(chǔ)到session域中迂曲。
- 默認(rèn)情況下,放入spring容器中的bean是單例的寥袭。
- 將來(lái)service層和dao層所有的類將放入到spring容器中路捧,所以默認(rèn)情況下這兩個(gè)層的類的實(shí)例都是單例的关霸,所以不能把數(shù)據(jù)聲明到屬性中。如果聲明到屬性中杰扫,將會(huì)成為共享的队寇,涉及到線程安全問(wèn)題。
創(chuàng)建時(shí)機(jī)和作用域的結(jié)合
- <font color="red">
scope="prototype" lazy-init="true"
</font> 在 context.getBean 時(shí)創(chuàng)建對(duì)象 - <font color="red">
scope="prototype" lazy-init="false"
</font> 在 context.getBean 時(shí)創(chuàng)建對(duì)象章姓,lazy-init為false失效英上。即在 scope 為 prototype 時(shí),始終在 context.getBean 時(shí)創(chuàng)建對(duì)象 - scope為singleton時(shí)啤覆,是默認(rèn)情況苍日。
Bean的生命周期
- Bean的生命周期方法
- instantiate bean 實(shí)例化 Bean 對(duì)象
- populate properties 給 Bean 對(duì)象注入屬性
- 如果 Bean 實(shí)現(xiàn) BeanNameAware 執(zhí)行 setBeanName
- 如果 Bean 實(shí)現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext
- 如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessBeforeInitialization
- 如果 Bean 實(shí)現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet
- 調(diào)用 Bean 中自定義的 init-method 方法
- 如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization
- 執(zhí)行業(yè)務(wù)邏輯代碼
- 如果 Bean 實(shí)現(xiàn) DisposableBean 執(zhí)行 destroy
- 調(diào)用 Bean 中自定義的 destroy-method 方法
- Bean的生命周期測(cè)試代碼
- HelloWorld.java
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class HelloWorld implements BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean { private String info; public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } public HelloWorld() { System.out.println("第一步:instantiate bean 實(shí)例化Bean對(duì)象"); } public void show() { System.out.println("第九步:show time 執(zhí)行業(yè)務(wù)邏輯代碼"); } public void myInit() { System.out.println("第七步:調(diào)用 Bean 中自定義的 init-method 方法"); } public void myDestroy() { System.out.println("第十一步:調(diào)用 Bean 中自定義的 destroy-method 方法"); } @Override public void setBeanName(String arg0) { System.out.println("第三步:如果 Bean 實(shí)現(xiàn) BeanNameAware 執(zhí)行 setBeanName" + info); } @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { System.out.println("第四步:如果 Bean 實(shí)現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("第六步:如果 Bean 實(shí)現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet"); } @Override public void destroy() throws Exception { System.out.println("第十步:如果 Bean 實(shí)現(xiàn) DisposableBean 執(zhí)行 destroy"); } }
- MyProcessor.java
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyProcessor implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException { System.out.println("第八步:如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization"); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("第五步:如果存在類實(shí)現(xiàn) BeanPostProcessor 執(zhí)行postProcessBeforeInitialization"); return arg0; } }
- applicationContext.xml
<?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="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy"> <property name="info" value="你好啊"></property> </bean> <!-- 此類是針對(duì)所有其他bean類的 --> <bean id="myProcessor" class="com.zhangquanli.spring.life.MyProcessor"/> </beans>
- HelloWorldTest
import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class HelloWorldTest { @Test public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.show(); context.close(); } }
- Bean的生命周期的說(shuō)明
- 第3步和第4步,是讓 Bean 了解 spring 容器窗声。
- 第5步和第8步相恃,可以針對(duì)指定 的Bean 使用動(dòng)態(tài)代理進(jìn)行功能增強(qiáng)。
- 第6步和第10步笨觅,可以實(shí)現(xiàn)指定的接口來(lái)完成 init 和 destroy 操作拦耐。
- 在開(kāi)發(fā)中,一般不使用第6步和第10步见剩,因?yàn)榈?步和第11步也可以完成 init 和 destroy 的操作杀糯。同時(shí),第7步和第11步的初始化和銷毀操作無(wú)耦合苍苞,只需要在配置文件制定初始化和銷毀的方法固翰。
<bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy"> <property name="info" value="你好啊"></property> </bean>
- Bean的生命周期的總結(jié)
- 增強(qiáng) Bean 的功能,可以實(shí)現(xiàn) BeanPostProcessor 來(lái)完成羹呵。
- 初始化和銷毀操作骂际,可以使用 bean 標(biāo)簽上的 init-method、destroy-method 方法來(lái)完成冈欢。
- <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果歉铝。</font>