主要是使用場景不同:一個singleton的Bean需要引用一個prototype的Bean; 一個無狀態的Bean需要引用一個有狀態的Bean; ... ; 等等情景下.
試想,我們的容器創建之後就加載了所有的Bean. 而BeanA中需要引用的BeanB是狀態個不確定的Bean. 那麼我們需要在每次需要BeanB的時候都重新讓容器加載一次嗎? 真是個笨拙的想法.
好在我們有cglib.
cglib爲我們動態的構造BeanB的子類, 當我們的BeanA需要BeanB的時候, cglib把這個子類對象給BeanA.
看代碼說話:
- /**
- * 我們把這個類作爲BeanB.
- * (Hp就是血量... 遊戲中某個英雄的血量總在變化)
- * (比如說我們希望通過英雄名找到的英雄的血是實時變化的. )
- */
- public class HpDaoImpl implements HpDao
- {
- @Override
- public int getHp()
- {
- // 返回0~100之間的隨即數
- return (int)(Math.random() * 100);
- }
- }
這是beanB的定義. 注意有個scope="prototype". 再請注意是全部小寫的prototype.
- <bean id="hpDao" class="org.mycompany.spring.aop.dao.impl.HpDaoImpl" scope="prototype" />
// -----------------------------------------------------------------------------
接下來是BeanA.
- /**
- * 我們把這個類作爲BeanA.
- * 這是一個抽象類. 爲什麼要抽象? 因爲有個抽象方法..
- * 既然抽象了, 就不能final... 切記切記
- */
- public abstract class HpServiceImpl implements HpService
- {
- // protected修飾
- protected HpDao hpDao = getHpDao();
- /*
- * 這個方法是抽象的.
- * 返回的是cglib構造的BeanB的子類.
- */
- public abstract HpDao getHpDao();
- @Override
- public int getHp()
- {
- // 調用原型BeanB的方法
- return hpDao.getHp();
- }
- }
再看看BeanA的定義:
- <bean id="hpService" class="org.mycompany.spring.aop.service.impl.HpServiceImpl">
- <lookup-method name="getHpDao" bean="hpDao" />
- </bean>
解釋:
lookup-method中name是BeanA中的抽象方法的名字.這裏這個方法的用途是得到由cglib構造的BeanB的動態子類.
lookup-mentod中bean是BeanB的類型.也就是cglib構造的BeanB的動態子類的父類型...目的當然是父類的句柄可以引用子類:用這個父類型引用構造出來的動態子類.
// -----------------------------------------------------------------------------
講解完畢.
實驗一下:
- public static void main(String[] args)
- {
- ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring/application-*.xml");
- // print: false
- if(context.getBean("hpDao") == context.getBean("hpDao"))
- {
- System.out.println(true);
- }else
- {
- System.out.println(false);
- }
- // print: true
- if(context.getBean("hpService") == context.getBean("hpService"))
- {
- System.out.println(true);
- }else
- {
- System.out.println(false);
- }
- }
// -----------------------------------------------------------------------------
額外注意一下:
如果BeanB沒有寫:scope="prototype" ...
那麼會出異常並提示你說:
No Scope registered for scope 'Prototype'
如果你添加scope='Prototype'...那還見鬼咧.還是這個錯.
所以我說了嘛...一定是小寫的prototype
spring出的這個異常太蠱禍人了. 在這裏我提出批評.