IOC的概念
- IOC Inversion of Controller 控制反轉(zhuǎn)。
- IOC 就是將對象的創(chuàng)建、初始化及銷毀交給 spring 容器來處理。
ApplicationContext 與 BeanFactory 的關(guān)系
- ApplicationContext 是 BeanFactory 的子接口。
- BeanFactory 采用延遲加載的方案,在getBean時才會實例化Bean。
- XmlBeanFactory
public void test4() { BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); beanFactory.getBean("helloWorld"); } // 經(jīng)過測試,BeanFactory在getBean時才實例化Bean。 - ApplicationContext 在配置文件加載時,就會初始化Bean,并且提供不同應(yīng)用層的實現(xiàn)。在開發(fā)中我們一般使用 ApplicationContext 的實現(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開發(fā)中常用
Bean的實例化方式
- 無參構(gòu)造方法
- 編寫配置文件
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>- 編寫測試方法
public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.show(); } - 編寫配置文件
- 靜態(tài)工廠方法
- 編寫工廠類,在工廠類中提供一個靜態(tài)方法,返回Bean對象
public class HelloWorldFactory { public static HelloWorld getInstance() { return new HelloWorld(); } }- 編寫配置文件
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>- 編寫測試方法
public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld2"); helloWorld.show(); } - 實例工廠方法
- 編寫工廠類,在工廠類中提供一個非靜態(tài)方法,返回Bean對象
public class HelloWorldFactory2 { public HelloWorld getInstance() { return new HelloWorld(); } }- 編寫配置文件
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>- 編寫測試方法
public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3"); helloWorld.show(); }
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="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
<alias name="helloWorld" alias="a"/>
<alias name="helloWorld" alias="b"/>
<alias name="helloWorld" alias="c"/>
</beans>
- 編寫測試方法
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)建時機
- 在 bean 標簽中有 lazy-init 屬性
- default,相當于 false,在 spring 容器啟動的時候創(chuàng)建對象。
- true,在 context.getBean 時創(chuàng)建對象。
- false,在 spring 容器啟動的時候創(chuàng)建對象。
- lazy-init 屬性的意義
- 如果把 lazy-init 設(shè)置為 true ,則當 spring 容器啟動的時候,檢測不到任何錯誤,這樣會存在很大的安全性隱患。所以一般情況應(yīng)該設(shè)置 lazy-init 為 false/default 。
- 但是如果一個bean中有一個屬性,該屬性含有大量的數(shù)據(jù),這個時候不希望該bean過早的停留在內(nèi)存中,這個時候需要用到 lazy-int 為 true 。
Bean的作用域
- 在 bean 標簽中有 scope 屬性,用于描述 bean 的作用域。
- singleton,單例模式,代表在 spring ioc 容器中只有一個 bean 實例。(默認的scope)
- prototype,多例模式,每一次從 spring ioc 容器中獲取,都會返回一個新實例。
- request,用在web開發(fā)中,通過 request.setAttribute() 將 bean 對象存儲到request域中。
- session,用在web開發(fā)中,通過 session.setAttribute() 將 Bean 對象存儲到session域中。
- 默認情況下,放入spring容器中的bean是單例的。
- 將來service層和dao層所有的類將放入到spring容器中,所以默認情況下這兩個層的類的實例都是單例的,所以不能把數(shù)據(jù)聲明到屬性中。如果聲明到屬性中,將會成為共享的,涉及到線程安全問題。
創(chuàng)建時機和作用域的結(jié)合
- <font color="red">
scope="prototype" lazy-init="true"</font> 在 context.getBean 時創(chuàng)建對象 - <font color="red">
scope="prototype" lazy-init="false"</font> 在 context.getBean 時創(chuàng)建對象,lazy-init為false失效。即在 scope 為 prototype 時,始終在 context.getBean 時創(chuàng)建對象 - scope為singleton時,是默認情況。
Bean的生命周期
- Bean的生命周期方法
- instantiate bean 實例化 Bean 對象
- populate properties 給 Bean 對象注入屬性
- 如果 Bean 實現(xiàn) BeanNameAware 執(zhí)行 setBeanName
- 如果 Bean 實現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext
- 如果存在類實現(xiàn) BeanPostProcessor 執(zhí)行postProcessBeforeInitialization
- 如果 Bean 實現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet
- 調(diào)用 Bean 中自定義的 init-method 方法
- 如果存在類實現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization
- 執(zhí)行業(yè)務(wù)邏輯代碼
- 如果 Bean 實現(xiàn) DisposableBean 執(zhí)行 destroy
- 調(diào)用 Bean 中自定義的 destroy-method 方法
- Bean的生命周期測試代碼
- 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 實例化Bean對象"); } 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 實現(xiàn) BeanNameAware 執(zhí)行 setBeanName" + info); } @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { System.out.println("第四步:如果 Bean 實現(xiàn) BeanFactoryAware 或 ApplicationContextAware 執(zhí)行 setBeanFactory 或 setApplicationContext"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("第六步:如果 Bean 實現(xiàn) InitializingBean 執(zhí)行 afterPropertiesSet"); } @Override public void destroy() throws Exception { System.out.println("第十步:如果 Bean 實現(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("第八步:如果存在類實現(xiàn) BeanPostProcessor 執(zhí)行postProcessorAfterInitialization"); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("第五步:如果存在類實現(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> <!-- 此類是針對所有其他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的生命周期的說明
- 第3步和第4步,是讓 Bean 了解 spring 容器。
- 第5步和第8步,可以針對指定 的Bean 使用動態(tài)代理進行功能增強。
- 第6步和第10步,可以實現(xiàn)指定的接口來完成 init 和 destroy 操作。
- 在開發(fā)中,一般不使用第6步和第10步,因為第7步和第11步也可以完成 init 和 destroy 的操作。同時,第7步和第11步的初始化和銷毀操作無耦合,只需要在配置文件制定初始化和銷毀的方法。
<bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy"> <property name="info" value="你好啊"></property> </bean> - Bean的生命周期的總結(jié)
- 增強 Bean 的功能,可以實現(xiàn) BeanPostProcessor 來完成。
- 初始化和銷毀操作,可以使用 bean 標簽上的 init-method、destroy-method 方法來完成。
- <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果。</font>