1. 程式人生 > >Spring入門之四-------Spring實例化Bean的其他知識點

Spring入門之四-------Spring實例化Bean的其他知識點

模式 mooc display cte ondestroy i++ 配置 lena 簡化

一、懶加載

技術分享圖片
public class Bean1 {

    public Bean1() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
}
Bean1 技術分享圖片
public class Bean2 {

    public Bean2() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
}
Bean2
<bean id="bean1" class="com.imooc.springClass4.others.Bean1" lazy-init="false"/>
<bean id="bean2" class="com.imooc.springClass4.others.Bean2" lazy-init="true"/>
@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    System.out.println(
"============ApplicationContext has been create============"); Bean1 bean1 = context.getBean("bean1", Bean1.class); System.out.println("bean1 = " + bean1); System.out.println(); Bean2 bean2 = context.getBean("bean2", Bean2.class); System.out.println("bean2 = " + bean2); System.out.println(); }

輸出

Bean1:com.imooc.springClass4.others.Bean1@49438269 has been created
============ApplicationContext has been create============
bean1 = com.imooc.springClass4.others.Bean1@49438269

Bean2:com.imooc.springClass4.others.Bean2@2462cb01 has been created
bean2 = com.imooc.springClass4.others.Bean2@2462cb01

結論:bean1沒有設定懶加載,所以Spring在加載上下文的時候就已經創建了bean1;bean2沒有設定懶加載,所以bean2在被需要的時候才創建。

如果想設定當前xml中所有的bean都默認開啟懶加載,可通過設定default-lazy-init="false"實現:

<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"
       default-lazy-init="false"
>
...
</beans>

二、Bean別名

技術分享圖片
public class Bean3 {

    public Bean3() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
}
Bean3

方式一:通過name屬性創建別名

<bean id="bean3-1" name="bean3-2, bean3-3" class="com.imooc.springClass4.others.Bean3"/>

上面代碼表示:創建一個Bean3,id為bean3-1,再給取兩個別名:bean3-2、bean3-3

方式二:通過alias標簽創建別名

<alias name="bean3-1" alias="bean3-4"/>

上面代碼表示:給bean3-1取一個別名:bean3-4

測試

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

    Bean3 bean3_1 = context.getBean("bean3-1", Bean3.class);
    System.out.println("bean3_1 = " + bean3_1);
    System.out.println();

    Bean3 bean3_2 = context.getBean("bean3-2", Bean3.class);
    System.out.println("bean3_2 = " + bean3_2);
    System.out.println();

    Bean3 bean3_3 = context.getBean("bean3-3", Bean3.class);
    System.out.println("bean3_3 = " + bean3_3);
    System.out.println();

    Bean3 bean3_4 = context.getBean("bean3-4", Bean3.class);
    System.out.println("bean3_4 = " + bean3_4);
    System.out.println();    
}

輸出

bean3_1 = com.imooc.springClass4.others.Bean3@1190200a
bean3_2 = com.imooc.springClass4.others.Bean3@1190200a
bean3_3 = com.imooc.springClass4.others.Bean3@1190200a
bean3_4 = com.imooc.springClass4.others.Bean3@1190200a

可以看到所有的bean3_?的地址都是一樣的。

三、引入其他xml

技術分享圖片
public class Bean4 {

    public Bean4() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
}
Bean4

resources目錄下創建spring-1.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="bean4" class="com.imooc.springClass4.others.Bean4"/>
</beans>

調整之前的spring.xml,增加

<import resource="spring-1.xml"/>

測試

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Bean4 bean4
= context.getBean("bean4", Bean4.class); System.out.println("bean4 = " + bean4); System.out.println(); }

輸出

bean4 = com.imooc.springClass4.others.Bean4@6a2f6f80

可以看到我們通過new ClassPathXmlApplicationContext("spring.xml")的方式引用spring.xml,由於spring.xml中import了spring-1.xml,所以spring-1.xml中定義的bean4也被實例化了。

四、方法註入

可能存在如下場景:Class A 的某個方法依賴於Class B的實例,Class A使用scope=singleton單例模式,但是Class A每次執行方法的時候都希望獲取一個新的Class B的實例,這個時候就用到了方法註入。舉例:

public class Bean5 {
    public Bean5() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
}
public abstract class Bean6 {

    public Bean6() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }

    protected abstract Bean5 createBean5();
    
    public void printBean5() {
        System.out.println("createBean5().toString() = " + createBean5().toString());
    }
}

從上面代碼我們看到,Bean6的printBean5方法是依賴於Bean5的實例的,如果該方法每次執行都想獲得一個Bean5的實例,那麽:

  1. Bean6中聲明一個abstract方法,返回Bean5
  2. Bean6的printBean5方法需要使用Bean5時直接飲用上面的abstract方法

xml配置如下:註意bean5需要時prototype模式

<bean id="bean5" class="com.imooc.springClass4.others.Bean5" scope="prototype"/>
<bean id="bean6" class="com.imooc.springClass4.others.Bean6">
    <lookup-method name="createBean5" bean="bean5"/>
</bean>

測試:

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
   
    for (int i = 0; i < 10; i++) {
        Bean6 bean6 = context.getBean("bean6", Bean6.class);
        bean6.printBean5();
    }
}

輸出:

Bean5:com.imooc.springClass4.others.Bean5@19b843ba has been created
createBean5().toString() = com.imooc.springClass4.others.Bean5@19b843ba
Bean5:com.imooc.springClass4.others.Bean5@64ec96c6 has been created
createBean5().toString() = com.imooc.springClass4.others.Bean5@64ec96c6
Bean5:com.imooc.springClass4.others.Bean5@77659b30 has been created
createBean5().toString() = com.imooc.springClass4.others.Bean5@77659b30
Bean5:com.imooc.springClass4.others.Bean5@456d6c1e has been created
createBean5().toString() = com.imooc.springClass4.others.Bean5@456d6c1e
Bean5:com.imooc.springClass4.others.Bean5@1e13529a has been created
createBean5().toString() = com.imooc.springClass4.others.Bean5@1e13529a
......

可以看到Bean6.printBean5()方法每次拿到的Bean5都是不同的實例

五、init-method和destroy-method

1. 如果需要在Bean實例化完成之後執行一些邏輯,可以有如下兩種方法:

(1)使用init-method

(2)讓Bean實現InitializingBean接口

2. 如果需要在Bean銷毀之前執行一些邏輯,也有兩種方法:

(1)使用destroy-method

(2)讓Bean實現DisposableBean接口

例如:

public class Bean7 implements InitializingBean, DisposableBean {

    public Bean7() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }

    public void onInit() {
        System.out.println(this.getClass().getSimpleName() + ":" + "onInit");
    }

    public void onDestroy() {
        System.out.println(this.getClass().getSimpleName() + ":" + "onDestroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getClass().getSimpleName() + ":" + "afterPropertiesSet");
    }

    public void destroy() throws Exception {
        System.out.println(this.getClass().getSimpleName() + ":" + "destroy");
    }
}

afterPropertiesSet()和destroy()是針對接口的實現。相應的xml配置:

<bean id="bean7" class="com.imooc.springClass4.others.Bean7" init-method="onInit" destroy-method="onDestroy"/>

測試:

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

    Bean7 bean7 = context.getBean("bean7", Bean7.class);
    System.out.println("bean7 = " + bean7);

context.close(); }

輸出:

Bean7:com.imooc.springClass4.others.Bean7@57cf54e1 has been created
Bean7:afterPropertiesSet
Bean7:onInit
bean7 = com.imooc.springClass4.others.Bean7@57cf54e1
Bean7:destroy
Bean7:onDestroy

如果想設定當前xml中所有的bean都有相同的init-method和destroy-method,可通過設定default-init-method="????"、default-destroy-method="????"實現:

<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"
       default-init-method="onInit"
       default-destroy-method="onDestroy"
>
</beans>

六、parent bean

可能存在如下場景:有很多Class繼承於Class B,且Class B有很多的property,當我們需要實例化很多Class B子類的時候,如果這些子類從Class B繼承的propertiy值基本相同,那麽通過xml創建這些子類是一件很繁重的事情,並且會存在很多類似的重復性的代碼出現。這種情況下,有如下解決辦法,舉例說明:

public class Bean8 {

    public Bean8() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
    private String name;
    private Integer age;
    //get/set...
}
public class Bean8_1 extends Bean8{

    public Bean8_1() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
    private String address;
    private Integer height;
    //get/set/toString...    
}
public class Bean8_2 extends Bean8{

    public Bean8_2() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }
    private String email;
    private Integer weight;
    //get/set/toString...
}
<bean id="bean8" class="com.imooc.springClass4.others.Bean8" abstract="true">
    <property name="name" value="zhang3"/>
    <property name="age" value="33"/>
</bean>
<bean id="bean8_1" class="com.imooc.springClass4.others.Bean8_1" parent="bean8">
    <property name="age" value="34"/>
    <property name="address" value="JiangSu SuZhou"/>
    <property name="height" value="155"/>
</bean>
<bean id="bean8_2" class="com.imooc.springClass4.others.Bean8_2" parent="bean8">
    <property name="age" value="35"/>
    <property name="email" value="[email protected]"/>
    <property name="weight" value="65"/>
</bean>

在xml中:

  1. 定義bean8,且設定abstracy=true,設定name和age的值
  2. 實例化bean8-1,且設定parent=bean8,重新設定age=34,設定address和height的值
  3. 實例化bean8-2,且設定parent=bean8,重新設定age=35,設定email和weight的值

測試:

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  
    Bean8_1 bean8_1 = context.getBean("bean8_1", Bean8_1.class);
    System.out.println("bean8_1 = " + bean8_1);
    Bean8_2 bean8_2 = context.getBean("bean8_2", Bean8_2.class);
    System.out.println("bean8_2 = " + bean8_2);
}

輸出

bean8_1 = Bean8_1{address=‘JiangSu SuZhou‘, height=155‘, name=zhang3‘, age=34}
bean8_2 = Bean8_1{email=‘[email protected]‘, weight=65‘, name=zhang3‘, age=35}

這樣,我們就可以將Bean8子類的屬性值統一在bean8中賦值進去,且由於bean8被標註的abstract所以並不會被創建。

另外,即使Bean8_1和Bean8_2沒有繼承於Bean8,但是Bean8_1和Bean8_2都有name和age屬性,也可以用過類似的手段簡化我們的代碼,示例如下:

public class Bean9_1 {

    public Bean9_1() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }

    private String name;
    private Integer age;
    private String address;
    private Integer height;

    // get/set/toString......
}
public class Bean9_2{

    public Bean9_2() {
        System.out.println(this.getClass().getSimpleName() + ":" + this.toString() + " has been created");
    }

    private String name;
    private Integer age;
    private String email;
    private Integer weight;

    // get/get/toString...
}
<bean id="bean9" abstract="true">
    <property name="name" value="zhang3"/>
    <property name="age" value="33"/>
</bean>
<bean id="bean9_1" class="com.imooc.springClass4.others.Bean9_1" parent="bean9">
    <property name="age" value="34"/>
    <property name="address" value="JiangSu SuZhou"/>
    <property name="height" value="155"/>
</bean>
<bean id="bean9_2" class="com.imooc.springClass4.others.Bean9_2" parent="bean9">
    <property name="age" value="35"/>
    <property name="email" value="[email protected]"/>
    <property name="weight" value="65"/>
</bean>

和之前bean8的區別就是,定義bean9的時候沒有對應的Class

測試:

@Test
public void testBean() throws Exception {
    final AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
 
    Bean9_1 bean9_1 = context.getBean("bean9_1", Bean9_1.class);
    System.out.println("bean9_1 = " + bean9_1);
    Bean9_2 bean9_2 = context.getBean("bean9_2", Bean9_2.class);
    System.out.println("bean9_2 = " + bean9_2);
}

輸出

bean9_1 = Bean9_1{name=‘zhang3‘, age=34, address=‘JiangSu SuZhou‘, height=155}
bean9_2 = Bean9_2{name=‘zhang3‘, age=35, email=‘[email protected]‘, weight=65}

Spring入門之四-------Spring實例化Bean的其他知識點