2015年12月24日 星期四

工廠方法、lazy、初始、結束、繼承、depends-on、scope (Spring3.x 九)

※工廠方法、lazy、初始、結束

Book.java

public class Book {
    public static String getBookName() {
        String s = "七龍珠";
        System.out.println(s);
        return s;
    }
    
    public void ooo() {
        System.out.println("初始");
    }
    
    public void xxx() {
        System.out.println("結束");
    }
}

applicationContext.xml

<bean id="book1" class="book.vo.Book" init-method="ooo" destroy-method="xxx" />
<bean id="book2" class="book.vo.Book" factory-method="getBookName" lazy-init="true" />
    
<bean id="ca" class="java.util.Calendar" factory-method="getInstance" />
<bean id="result" factory-bean="ca" factory-method="getTime" />

測試類

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
Date date = (Date) appContext.getBean("result");
System.out.println(date);
    
((ClassPathXmlApplicationContext) appContext).close();

結果:
初始
Thu Dec 24 15:32:06 CST 2015
結束

※如果將book2的lazy拿掉,就會印出七龍珠了,或者呼叫book2才會去抓

※book2、ca、result可以用如下的想法比較容易了解
// book2
Book.getBookName();
    
// ca
Date date = Calendar.getInstance().getTime();
    
//result
date.getDate();


※getBookName()必需提供回傳值,否則會出「needs to have a non-void return type!」的錯

※scope 使用 prototype 時,在getBean 時才會去抓值;而 scope 使用預設的 singleton 在 new ClassPathXMLApplicationContext 時就會去抓,如果想和 prototype 一樣,可以用lazy="true"

※ init-method 裡的方法至少要 private void xxx(),不能有參數,如果沒有此方法會報錯
destroy-method 一定要將 ApplicationContext close 才會呼叫,但要將ApplicationContext 強轉成有 close 方法的子類,而且也必須是 singleton,annotation 用的是 @Bean

※如果有很多 class 都想用 init-method 或 destroy-method,每一個都要設很麻煩,所以 Spring 有提供設定,在 beans 裡用 default-init-method、default-destroy-init-method,在設定完 bean class 時才會呼叫,而且沒有寫方法,也不會報錯


※FactoryBean 介面

public class Book {
    private String bookName;
    private int bookMoney;
    
    public Book() {}
    
    public Book(int bookMoney, String bookName) {
        this.bookMoney = bookMoney;
        this.bookName = bookName;
    }
    
    //setter/getter...
}
------------------------------
public class BookFactoryBean implements FactoryBean<Book> {
    @Override
    public Book getObject() throws Exception {
        return new Book(90, "寶島少年");
    }
    
    @Override
    public Class<Book> getObjectType() {
        return Book.class;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}




<bean id="b" class="xxx.ooo.Book" p:bookName="七龍珠" p:bookMoney="65" />
<bean id="bfb" class="xxx.ooo.BookFactoryBean" />

※getBean("b") 時是之前的做法,使用 getBean("bfb") 就能看見效果了


※繼承

<bean id="book1" class="book.vo.Book" p:name="資治通鑑" p:money="2000" p:color="紅" p:size="A4" />
<bean id="comic1" class="book.vo.Comic" p:name="遊戲王" p:money="65" p:color="紅" p:size="A4" />
    
<bean id="book2" class="book.vo.Book" p:name="資治通鑑" p:money="2000" p:color="紅" p:size="A4" abstract="true" />
<bean id="comic2" class="book.vo.Comic" p:name="遊戲王" p:money="65" parent="book2" />

※book1和comic1有兩個屬性一樣,這時可以透過繼承的方法,變成book2和comic2,這時只要在測試類,呼叫comic2的color或size即可取得父類的值,當然重點是abstract和parent




※depends-on


<bean name="dao" class="xxx.Dao" depends-on="database" />
<bean id="database" class="ooo.xxx.Database" />

※dao在連資料庫時,必需取得database,設定depends-on可以保證database先實例化好再實例化dao




※scope


<bean id="book1" class="book.vo.Book" scope="singleton" />
<bean id="book2" class="book.vo.Book" scope="prototype" />

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    
System.out.println(appContext.getBean("book1"));
System.out.println(appContext.getBean("book1"));
System.out.println(appContext.getBean("book2"));
System.out.println(appContext.getBean("book2"));
    
((ClassPathXmlApplicationContext) appContext).close();

※結果
book.vo.Book@6df97b55
book.vo.Book@6df97b55
book.vo.Book@3cbbc1e0
book.vo.Book@35fb3008

※scope="singleton"為預設

※可以看出結果一、二行一模一樣,因為它是singleton

※只有用getBean才會有single的效果哦,如果用new或者反射的invoke就不會一模一樣了

※還有三種request、session、global session,都是用在web的

沒有留言:

張貼留言