Spring - lookup-method方式實現依賴注入

引言java

假設一個單例模式的bean A須要引用另一個非單例模式的bean B,爲了在咱們每次引用的時候都能拿到最新的bean B,咱們可讓bean A經過實現ApplicationContextWare來感知applicationContext(便可以得到容器上下文),從而能在運行時經過ApplicationContext.getBean(String beanName)的方法來獲取最新的bean B。可是若是用ApplicationContextAware接口,就讓咱們與Spring代碼耦合了,違背了反轉控制原則(IoC,即bean徹底由Spring容器管理,咱們本身的代碼只須要用bean就能夠了)。spring

因此Spring爲咱們提供了方法注入的方式來實現以上的場景。方法注入方式主要是經過<lookup-method/>標籤。app

實例測試

下面咱們用一個例子來講明lookup-method的用法。ui

假設有一個果盤,果盤裏放了一些水果,好比蘋果,香蕉等,咱們但願咱們每次在果盤裏拿到的都是最新鮮的水果。spa

java代碼:prototype

// 定義一個水果類
public class Fruit { public Fruit() { System.out.println("I got Fruit"); } } // 蘋果
public class Apple extends Fruit { public Apple() { System.out.println("I got a fresh apple"); } } // 香蕉
public class Bananer extends Fruit { public Bananer () { System.out.println("I got a  fresh bananer"); } } // 水果盤,能夠拿到水果
public abstract class FruitPlate{ // 抽象方法獲取新鮮水果
    protected abstract Fruit getFruit(); }

spring配置:代理

<!-- 這是2個非單例模式的bean -->
<bean id="apple" class="cn.com.willchen.test.di.Apple" scope="prototype"/>
<bean id="bananer" class="cn.com.willchen.test.di.Bananer " scope="prototype"/>
 
<bean id="fruitPlate1" class="cn.com.willchen.test.di.FruitPlate">
    <lookup-method name="getFruit" bean="apple"/>
</bean>
<bean id="fruitPlate2" class="cn.com.willchen.test.di.FruitPlate">
    <lookup-method name="getFruit" bean="bananer"/>
</bean>

測試代碼:code

public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("classpath:resource/applicationContext.xml"); FruitPlate fp1= (FruitPlate)app.getBean("fruitPlate1"); FruitPlate fp2 = (FruitPlate)app.getBean("fruitPlate2"); fp1.getFruit(); fp2.getFruit(); }

測試結果:xml

I got Fruit

I got a fresh apple

I got Fruit

I got a fresh bananer

 

示例說明:

從上面例子咱們能夠看到,在代碼中,咱們沒有用到Spring的任何類和接口,實現了與Spring代碼的耦合。

其中,最爲核心的部分就是lookup-method的配置和FruitPlate.getFruit()方法。上面代碼中,咱們能夠看到getFruit()方法是個抽象方法,咱們並無實現它啊,那它是怎麼拿到水果的呢。這裏的奧妙就是Srping應用了CGLIB(動態代理)類庫。Spring在初始化容器的時候對配置<lookup-method/>的bean作了特殊處理,Spring會對bean指定的class作動態代理,代理<lookup-method/>標籤中name屬性所指定的方法,返回bean屬性指定的bean實例對象。每次咱們調用fruitPlate1或者fruitPlate2這2個bean的getFruit()方法時,實際上是調用了CGLIB生成的動態代理類的方法。關於CGLIB你們可自行在網上查閱。

lookup-method實現方式說明:

<bean class="beanClass">
    <lookup-method name="method" bean="non-singleton-bean"/>
</bean>

method是beanClass中的一個方法,beanClass和method是否是抽象都無所謂,不會影響CGLIB的動態代理,根據項目實際需求去定義。non-singleton-bean指的是lookup-method中bean屬性指向的必須是一個非單例模式的bean,固然若是不是也不會報錯,只是每次獲得的都是相同引用的bean(同一個實例),這樣用lookup-method就沒有意義了。

 

另外對於method在代碼中的簽名有下面的標準:

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

public|protected要求方法必須是能夠被子類重寫和調用的;

abstract可選,若是是抽象方法,CGLIB的動態代理類就會實現這個方法,若是不是抽象方法,就會覆蓋這個方法,因此沒什麼影響;

return-type就是non-singleton-bean的類型咯,固然能夠是它的父類或者接口。

no-arguments不容許有參數。

相關文章
相關標籤/搜索