02_Spring IOC(控制反轉(zhuǎn))

IOC的概念

  • IOC Inversion of Controller 控制反轉(zhuǎn)。
  • IOC 就是將對象的創(chuàng)建、初始化及銷毀交給 spring 容器來處理。

ApplicationContext 與 BeanFactory 的關(guān)系

  1. ApplicationContext 是 BeanFactory 的子接口。
  2. BeanFactory 采用延遲加載的方案,在getBean時才會實例化Bean。
    • XmlBeanFactory
    public void test4() {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        beanFactory.getBean("helloWorld");
    }
    // 經(jīng)過測試,BeanFactory在getBean時才實例化Bean。
    
  3. 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的實例化方式

  1. 無參構(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();
    }
    
  2. 靜態(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();
    }
    
  3. 實例工廠方法
    • 編寫工廠類,在工廠類中提供一個非靜態(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的別名

  1. 編寫配置文件
<?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>
  1. 編寫測試方法
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)建時機

  1. 在 bean 標簽中有 lazy-init 屬性
    • default,相當于 false,在 spring 容器啟動的時候創(chuàng)建對象。
    • true,在 context.getBean 時創(chuàng)建對象。
    • false,在 spring 容器啟動的時候創(chuàng)建對象。
  2. lazy-init 屬性的意義
    • 如果把 lazy-init 設(shè)置為 true ,則當 spring 容器啟動的時候,檢測不到任何錯誤,這樣會存在很大的安全性隱患。所以一般情況應(yīng)該設(shè)置 lazy-init 為 false/default 。
    • 但是如果一個bean中有一個屬性,該屬性含有大量的數(shù)據(jù),這個時候不希望該bean過早的停留在內(nèi)存中,這個時候需要用到 lazy-int 為 true 。

Bean的作用域

  1. 在 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域中。
  2. 默認情況下,放入spring容器中的bean是單例的。
    • 將來service層和dao層所有的類將放入到spring容器中,所以默認情況下這兩個層的類的實例都是單例的,所以不能把數(shù)據(jù)聲明到屬性中。如果聲明到屬性中,將會成為共享的,涉及到線程安全問題。

創(chuàng)建時機和作用域的結(jié)合

  1. <font color="red">scope="prototype" lazy-init="true"</font> 在 context.getBean 時創(chuàng)建對象
  2. <font color="red">scope="prototype" lazy-init="false"</font> 在 context.getBean 時創(chuàng)建對象,lazy-init為false失效。即在 scope 為 prototype 時,始終在 context.getBean 時創(chuàng)建對象
  3. scope為singleton時,是默認情況。

Bean的生命周期

  1. 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 方法
  2. 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();
        }
    }
    
  3. 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>
    
  4. Bean的生命周期的總結(jié)
    • 增強 Bean 的功能,可以實現(xiàn) BeanPostProcessor 來完成。
    • 初始化和銷毀操作,可以使用 bean 標簽上的 init-method、destroy-method 方法來完成。
    • <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果。</font>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容