Spring之方法注入

為什么要有方法注入:

假設(shè)有一個(gè)Bean 依賴(lài)于另一個(gè)Bean,兩個(gè)的生命周期卻不一樣的時(shí)候,光靠配置和注解不能很好地解決。
如:一個(gè)單例的Bean A和一個(gè)非單例的bean B, A 依賴(lài) B,每次容器只會(huì)初始化一次 A,B卻每次都需要重新創(chuàng)建,當(dāng) B成為A的屬性時(shí),A內(nèi)的B就無(wú)法每次重新創(chuàng)建,這樣要么放棄控制反轉(zhuǎn),要么得想新辦法解決這個(gè)問(wèn)題。
所以,Spring 通過(guò)方法注入,來(lái)實(shí)現(xiàn)動(dòng)態(tài)改變A內(nèi)的B,注入利用了容器的覆蓋受容器管理的bean方法的能力,從而返回指定名字的bean實(shí)例。
介紹兩個(gè)方法注入的方式,分別是查找注入,和方法替換

查找注入

Spring的方法注入依賴(lài)于CGLIB,需要添加Jar包com.springsource.cn.sf.cglib-2.2.0.jar,Spring通過(guò)CGLib動(dòng)態(tài)修改字節(jié)碼,所以可以用配置方式,使用代理覆蓋或攔截指定的方法動(dòng)態(tài)生成子類(lèi),可分為查找方法注入和替換方法注入。
用于注入方法返回結(jié)果,也就是說(shuō)能通過(guò)配置方式替換方法返回結(jié)果。

CGLib,一個(gè)操作字節(jié)碼的庫(kù),玩的溜的話(huà)是不是可以寫(xiě)動(dòng)態(tài)病毒?

查找注入的方法必須符合下面的規(guī)則

  • 必須有返回值
  • 可以是抽象的,但必須是public或protected修飾可以被子類(lèi)訪問(wèn)的
  • 必須是無(wú)參的
  • 不能是final修飾的

適用情況
Bean是有生命周期的,方法注入是為了使方法獨(dú)立于Bean。
比如一個(gè)單例(singleton)的Bean,依賴(lài)了一個(gè)非單例的(prototype)普通Bean,當(dāng)單例模式的Bean被銷(xiāo)毀時(shí),會(huì)導(dǎo)致這個(gè)普通Bean也會(huì)銷(xiāo)毀,為了解決,可以使不被銷(xiāo)毀,使用方法注入。

看個(gè)例子

一個(gè)bean,非單例模式的

package com.zing.method_injection;
/**
 * Created by zing on 16/5/18.
 */
public class BuityPeople {
    private static int ID = 0;
    private String name;
    private String cast;
    public BuityPeople() {
        ID++;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name + ID;
    }
    public String getCast() {
        return cast;
    }
    public void setCast(String cast) {
        this.cast = cast + ID;
    }
    @Override
    public String toString() {
        return "BuityPeople{" +
                "name='" + name + '\'' +
                ", cast='" + cast + '\'' +
                '}';
    }
}

另一個(gè)bean,單例模式的

package com.zing.method_injection;
/**
 * Created by zing on 16/5/18.
 */
public interface Movie {
    public BuityPeople getActor();
}

現(xiàn)在是Movie依賴(lài)BuityPeople,
寫(xiě)好配置,這里p 需要加頭

<bean id="buityPeople" class="com.zing.method_injection.BuityPeople" 
    p:name="群演"      p:cast="路人"      scope="prototype"></bean>
<bean id="movie" class="com.zing.method_injection.Movie" scope="singleton">
    <lookup-method name="getActor" bean="buityPeople"></lookup-method>
</bean>

這樣方法注入的例子就配置好了,我們寫(xiě)一段代碼,測(cè)試一下

public class TestLookupMethod {
    @Test
    public void getMovieStar() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Movie movie = context.getBean("movie", Movie.class);
        BuityPeople p1 = movie.getActor();
        BuityPeople p2 = movie.getActor();
        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}
測(cè)試結(jié)果

看出來(lái)演員是兩個(gè)不同的人,但是Movie對(duì)象一直是單例的,沒(méi)有變化。

坑:class字節(jié)碼的組成,ps:還沒(méi)看懂,提供給想了解的小伙伴

方法替換

寫(xiě)不下去了?。MG

這個(gè)是利用自己的方法去替換另一個(gè)bean的方法,適用場(chǎng)景未知,目前沒(méi)用過(guò)。

我們嘗試玩一下,用明星來(lái)演電影,把配角換成主角。還是用到了上面的BuityPeople類(lèi)

package com.zing.method_injection;
/**
 * Created by zing on 16/5/18.
 */
public class MovieStar {
    private BuityPeople getActor() {
        BuityPeople p = new BuityPeople();
        p.setName("普通明星");
        p.setCast("配角");
        return p;
    }
}
package com.zing.method_injection;
/**
 * Created by zing on 16/5/18.
 */
//一定要實(shí)現(xiàn)MethodReplacer接口
public class  SuperStar implements MethodReplacer{
    @Override
    public Object reimplement(Object o, Method method, Object[] objects) throws Throwable {
        BuityPeople p = new BuityPeople();
        p.setName("超級(jí)明星");
        p.setCast("主角");
        return p;
    }
}

添加配置

<bean id="movieStar" class="com.zing.method_injection.MovieStar">
    <replaced-method name="getActor" replacer="superStarMovie"></replaced-method>
</bean>
<bean id="superStarMovie" class="com.zing.method_injection.SuperStar"></bean>

配置完成寫(xiě)一段代碼測(cè)試一下

@Test
public void goodMovieStar() {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    System.out.println("測(cè)試前的演員————————————————————————");
    MovieStar movieStar1 = new MovieStar();
    System.out.println(movieStar1.getActor().toString());
    System.out.println("測(cè)試后的演員————————————————————————");
    MovieStar movieStar2 = context.getBean("movieStar", MovieStar.class);
    System.out.println(movieStar2.getActor().toString());
}
測(cè)試結(jié)果,getActor()被SuperStarMovie內(nèi)的方法替換了

大家看到了,方法被替換了,演員也換了,角色也換了。侵入性很強(qiáng)!所以一般不使用方法替換,只是使用第一種,查找注入。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容