去掉對Spring BeanFacotry的getBean方法的依賴

在使用Spring時,有時會碰到這種情況:
[quote]需要在一個類中使用一個非Singlton類型的Bean,比如每次方法調用都需要new一個新的Bean。但是,由於Spring的依賴注入是在Bean初始化完成之後進行的,而且只進行一次,因此就無法在每次方法調用時注入新的Bean。[/quote]
那麼如何解決這個問題呢,一般的做法可能是實現Spring的ApplicationContextAware接口,然後在沒個方法中顯示地調用ApplicationContext的getBean方法,當然這個Bean在Spring的配置文件中是配置成非Singlton的。如下面代碼所示:

public class ClazzA implements ApplicationContextAware{
private ApplicationContext applicationContext;

void setApplicationContext(ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}

public void methodA(){
Object bean = this.applicationContext.getBean("...");
...
}

public void methodB(){
Object bean = this.applicationContext.getBean("...");
...
}

...
}

上面的代碼可以解決我們之前說的問題,但是,這樣做就形成了對Spring框架代碼的依賴,降低了應用程序代碼的可以執行和可重用性。
不過不用擔心,Spring已經爲我們考慮到了這一點,並且提供了幾種更好的解決方案。下面講一下其中的兩種。這兩種方法Spring都是通過使用CGLIB自動生成字節碼來完成的。
解決方案一:Lookup Method。
仍然以上面的ClazzA爲例。這種方法需要將ClazzA定義爲抽象類,並在該類中定義一個抽象的createBean方法。修改後的代碼如下:

public abstract class ClazzA{
public void methodA(){
ClazzB bean = this.applicationContext.getBean("...");
...
}

public void methodB(){
ClazzB bean = this.applicationContext.getBean("...");
...
}

public abstract ClazzB createBean();
...
}

然後在Spring的配置文件中做如下定義:

<bean id="clazzB" class="edu.sjtu.spring.ClazzB" scope="prototype">
<!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->
<bean id="clazzA" class="edu.sjtu.spring.ClazzA">
<lookup-method name="createBean" bean="command"/>
</bean>

這樣定義之後,Spring就會使用CGLIB自動生成一個實現了createBean方法的ClazzA的一個實現類,並讓createBean返回ClazzB。
上面所說的那個createBean方法必須符合下面的方法簽名:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);


詳細信息可以參見Spring文檔的3.4節。
解決方案二:使用ServiceLocatorFactoryBean。
這種方案交第一種方案更加靈活一點,但是付出的代價是要單獨定一個工廠接口。這種方法在Spring的ServiceLocatorFactoryBean類的API文檔中有詳細介紹,這裏就不再累述了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章