Spring系列第九講 depend-on到底是幹什麼的?

qwer1030274531發表於2020-10-31

無依賴bean建立和銷燬的順序

我們先來看一下沒有任何依賴的bean的建立和銷燬的順序。

下面的xml中定義了3個bean:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="
       xmlns:xsi="
       xsi:schemaLocation="
    /spring-beans-4.3.xsd">
    <bean id="bean3" class="com.javacode2018.lesson001.demo7.NormalBean$Bean3"/>
    <bean id="bean2" class="com.javacode2018.lesson001.demo7.NormalBean$Bean2"/>
    <bean id="bean1" class="com.javacode2018.lesson001.demo7.NormalBean$Bean1"/></beans>12345678910

注意上面xml中bean定義順序是:bean3、bean2、bean1。

對應java程式碼如下:

package com.javacode2018.lesson001.demo7;import org.springframework.beans.factory.DisposableBean;/**
 * 無任何依賴的bean建立的順序
 */public class NormalBean {
    public static class Bean1 implements DisposableBean {
        public Bean1() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean2 implements DisposableBean {
        public Bean2() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean3 implements DisposableBean {
        public Bean3() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }}1234567891011121314151617181920212223242526272829303132333435363738394041424344

上面程式碼中使用到了DisposableBean介面,這個是spring容器提供的一個介面,這個介面中有個destroy方法,我們的bean類可以實現這個介面,當我們呼叫容器的close方法關閉容器的時候,spring會呼叫容器中所有bean的destory方法,用來做一些清理的工作,這個以後還會細講的。

上面幾個類中構造方法和destory方法中都有輸出。

下面我們來搞個測試用例看一下spring容器啟動和關閉的過程中,定義的3個bean的建立和銷燬的順序。

package com.javacode2018.lesson001.demo7;import com.javacode2018.lesson001.demo5.IocUtils;import org.junit.Test;import org.springframework.context.support.ClassPathXmlApplicationContext;/**
 * dependon詳解
 */public class DependOnTest {
    /**
     * 無依賴的bean建立和銷燬的順序
     */
    @Test
    public void normalBean() {
        System.out.println("容器啟動中!");
        String beanXml = "classpath:/com/javacode2018/lesson001/demo7/normalBean.xml";
        ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
        System.out.println("容器啟動完畢,準備關閉spring容器!");
        //關閉容器
        context.close();
        System.out.println("spring容器已關閉!");
    }}1234567891011121314151617181920212223242526

執行上面的normalBean方法,輸出:

容器啟動中!class com.javacode2018.lesson001.demo7.NormalBean$Bean3 constructor!class com.javacode2018.lesson001.demo7.NormalBean$Bean2 constructor!class com.javacode2018.lesson001.demo7.NormalBean$Bean1 constructor!容器啟動完畢,準備關閉spring容器!class com.javacode2018.lesson001.demo7.NormalBean$Bean1 destroy()class com.javacode2018.lesson001.demo7.NormalBean$Bean2 destroy()class com.javacode2018.lesson001.demo7.NormalBean$Bean3 destroy()spring容器已關閉!123456789

bean的定義結合上面輸出我們來對比一下:

bean定義順序 建立順序 銷燬順序
bean3 bean3 bean1
bean2 bean2 bean2
bean1 bean1 bean3

從輸出中可以得到2點結論:

  1. bean物件的建立順序和bean xml中定義的順序一致

  2. bean銷燬的順序和bean xml中定義的順序相反

透過構造器強依賴bean建立和銷燬順序

我們將上面案例改造一下,透過建構函式注入的方式使bean之間產生強依賴。

package com.javacode2018.lesson001.demo7;import org.springframework.beans.factory.DisposableBean;/**
 * 強依賴的bean建立和銷燬順序
 */public class StrongDependenceBean {
    public static class Bean1 implements DisposableBean {
        public Bean1() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean2 implements DisposableBean {
        private Bean1 bean1;
        public Bean2(Bean1 bean1) { //@1
            this.bean1 = bean1;
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean3 implements DisposableBean {
        private Bean2 bean2;
        public Bean3(Bean2 bean2) { //@2
            this.bean2 = bean2;
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

程式碼解釋:

@1:建立Bean2的時候需要傳入一個bean1物件,對bean1產生了強依賴

@2:建立Bean3的時候需要傳入一個bean2物件,對bean2產生了強依賴

依賴關係是:

bean3->bean2->bean11

對應的配置(strongDependenceBean.xml):

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="
       xmlns:xsi="
       xsi:schemaLocation="
    /spring-beans-4.3.xsd">
    <bean id="bean3" class="com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean3">
        <constructor-arg index="0" ref="bean2"/> //@1
    </bean>
    <bean id="bean2" class="com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean2">
        <constructor-arg index="0" ref="bean1"/> //@2
    </bean>
    <bean id="bean1" class="com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean1">
    </bean></beans>123456789101112131415

注意上面xml中bean定義順序是:bean3、bean2、bean1。

@1:bean3中透過構造器注入bean2

@2:bean2中透過構造器注入bean1

DependOnTest中建立一個測試用例,如下:

/**
 * 強依賴的bean的建立和銷燬順序測試
 */@Testpublic void strongDependenceBean() {
    System.out.println("容器啟動中!");
    String beanXml = "classpath:/com/javacode2018/lesson001/demo7/strongDependenceBean.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println("容器啟動完畢,準備關閉spring容器!");
    context.close();
    System.out.println("spring容器已關閉!");}123456789101112

執行strongDependenceBean方法輸出:

容器啟動中!class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean1 constructor!class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean2 constructor!class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean3 constructor!容器啟動完畢,準備關閉spring容器!class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean3 destroy()class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean2 destroy()class com.javacode2018.lesson001.demo7.StrongDependenceBean$Bean1 destroy()spring容器已關閉!123456789

bean的定義結合上面輸出我們來對比一下:

bean定義順序 依賴順序(下面依賴上面的) 建立順序 銷燬順序
bean3 bean1 bean1 bean3
bean2 bean2 bean2 bean2
bean1 bean3 bean3 bean1

從輸出中可以得到2點結論:

  1. bean物件的建立順序和bean依賴的順序一致

  2. bean銷燬的順序和bean建立的順序相反

透過depend-on干預bean建立和銷燬順序

上面看到了對於無依賴的bean,透過定義的順序確實可以干預bean的建立順序,透過強依賴也可以干預bean的建立順序。

那麼如果xml中定義的bean特別多,而有些bean之間也沒有強依賴關係,此時如果想去調整bean的建立和銷燬的順序,得去調整xml中bean的定義順序,或者去加強依賴,這樣是非常不好的,spring中可以透過depend-on來解決這些問題,在不調整bean的定義順序和強加依賴的情況下,可以透過透過depend-on屬性來設定當前bean的依賴於哪些bean,那麼可以保證depend-on指定的bean在當前bean之前先建立好,銷燬的時候在當前bean之後進行銷燬。

depend-on使用方式:

<bean id="bean1" class="" depend->

depend-on:設定當前bean依賴的bean名稱,可以指定多個,多個之間可以用”,;空格“進行分割

上面不管bean2,bean2,bean4在任何地方定義,都可以確保在bean1建立之前,會先將bean2,bean3,bean4建立好,表示bean1依賴於這3個bean,可能bean1需要用到bean2、bean3、bean4中生成的一些資源或者其他的功能等,但是又沒有強制去在bean1類中透過屬性定義強依賴的方式去依賴於bean2、bean3、bean4;當然銷燬的時候也會先銷燬當前bean,再去銷燬被依賴的bean,即先銷燬bean1,再去銷燬depend-on指定的bean。

下面我們來個案例看一下:

dependOnBean.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="
       xmlns:xsi="
       xsi:schemaLocation="
    /spring-beans-4.3.xsd">
    <bean id="bean3" class="com.javacode2018.lesson001.demo7.NormalBean$Bean3" depends-on="bean2,bean1"/>
    <bean id="bean2" class="com.javacode2018.lesson001.demo7.NormalBean$Bean2"/>
    <bean id="bean1" class="com.javacode2018.lesson001.demo7.NormalBean$Bean1"/></beans>12345678910

上面xml中先定義的bean3,然後定義了bean2和bean1,並且指定了bean3的depend->

上面xml對應的java程式碼如下: shandong/

package com.javacode2018.lesson001.demo7;import org.springframework.beans.factory.DisposableBean;/**
 * 透過depend-on來干預bean建立和銷燬順序
 */public class DependOnBean {
    public static class Bean1 implements DisposableBean {
        public Bean1() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean2 implements DisposableBean {
        public Bean2() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }
    public static class Bean3 implements DisposableBean {
        public Bean3() {
            System.out.println(this.getClass() + " constructor!");
        }
        @Override
        public void destroy() throws Exception {
            System.out.println(this.getClass() + " destroy()");
        }
    }}1234567891011121314151617181920212223242526272829303132333435363738394041424344

DependOnTest中建立測試用例: nanchang/

/**
 * 透過depend-on來干預bean建立和銷燬順序
 */@Testpublic void dependOnBean() {
    System.out.println("容器啟動中!");
    String beanXml = "classpath:/com/javacode2018/lesson001/demo7/dependOnBean.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println("容器啟動完畢,準備關閉spring容器!");
    context.close();
    System.out.println("spring容器已關閉!");}123456789101112

執行dependOnBean方法輸出: lanzhou/

容器啟動中!class com.javacode2018.lesson001.demo7.NormalBean$Bean2 constructor!class com.javacode2018.lesson001.demo7.NormalBean$Bean1 constructor!class com.javacode2018.lesson001.demo7.NormalBean$Bean3 constructor!容器啟動完畢,準備關閉spring容器!class com.javacode2018.lesson001.demo7.NormalBean$Bean3 destroy()class com.javacode2018.lesson001.demo7.NormalBean$Bean1 destroy()class com.javacode2018.lesson001.demo7.NormalBean$Bean2 destroy()spring容器已關閉!123456789

總結 haerbin/

  • 無依賴的bean建立順序和定義的順序一致,銷燬順序剛好相反

  • 透過構造器強依賴的bean,會先建立構造器引數中對應的bean,然後才會建立當前bean,銷燬順序剛好相反

  • depend-on可以指定檔期bean依賴的bean,透過這個可以確保depend-on指定的bean在當前bean建立之前先建立好,銷燬順序剛好相反

  • bean的銷燬順序和bean建立的順序相反


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30239065/viewspace-2731316/,如需轉載,請註明出處,否則將追究法律責任。

相關文章