天天看點

Spring IOC的一些進階特性

1.Lookup方法注入

        在大部分的應用場景中,容器中的大部分bean是singleton類型的。當一個單例bean需要和另外一個單例bean協作時,或者一個非單例bean要引用另外一個非單例bean時,通常情況下将一個bean定義為另外一個bean的屬性值就行了。不過對于具有不同生命周期的bean來說這樣做就會有問題了,比如在調用一個單例類型bean A的某個方法,需要引用另一個非單例(prototype)類型bean B,對于bean A來說,容器隻會建立一次,這樣就沒法在需要的時候每次讓容器為bean A提供一個新的bean

B執行個體。

        Lookup方法具有使容器覆寫受容器管理的bean方法的能力,進而傳回指定名字的bean執行個體。在上述場景中,Lookup方法注入适用于原型bean。 Lookup方法注入的内部機制是Spring利用了CGLIB庫在運作時生成二進制代碼的功能,通過動态建立Lookup方法bean的子類進而達到複寫Lookup方法的目的。

        為了使動态子類起作用,Spring容器要子類化的類不能是

final

,并且需要覆寫的方法也不能是

final

。同樣的,要測試一個包含

抽象

方法的類也稍微有些不同,你需要子集編寫它的子類提供該

抽象

方法的實作。最後,作為方法注入目标的bean不能是序列化的。在Spring

3.2之後再也沒必要添加CGLIB到classpath,因為CGLIB的類打包在了org.springframework下并且在Spring核心JAR中有所描述。這樣做既友善,又避免了與其他使用了不同版本CGLIB的項目的沖突。

        假如現在有2個類:Clerk和ClerkManager,其中ClerkManager依賴于Clerk,即ClerkManager持有類型為Clerk的私有屬性,現在我們想讓Clerk been的作用域為singleton,而ClerkManager been的作用域為prototype,如果不做任何處理直接在ClerkManager been中設定Clerk屬性,就會出現問題,即每次應用的Clerk been都是同一個,無法達到預期的效果。這個時候我們可以使用Spring的Lookup方法注入來達到在每次引用Clerk屬性的時候都會動态建立一個新的Clerk

been的目的。一下是Clerk和ClerkManager的代碼:

package com.ioc.lookup;

public class Clerk {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

}
           
package com.ioc.lookup;

public abstract class ClerkManager {
	private Clerk clerk;
	
    public Object process() {
        //調用createClerk()方法動态生成Clerk對象
        Clerk Clerk=createClerk();
        return Clerk;
    }

    //這個動态生成Clerk對象的方法,這是個抽象方法,Spring容器會自動覆寫createClerk()方法的實作。
    protected abstract Clerk createClerk();

	public Clerk getClerk() {
		return clerk;
	}

	public void setClerk(Clerk clerk) {
		this.clerk = clerk;
	}
    
}
           

        接着我們在applicationContext.xml中配置如上類的bean:

<bean id="clerk" class="com.ioc.lookup.Clerk" scope="prototype">
		<property name="name" value="Tom"></property>
		<property name="age" value="20"></property>
	</bean>
	
	<bean id="clerkManager" class="com.ioc.lookup.ClerkManager" scope="singleton">
		<lookup-method name="createClerk" bean="clerk"/>
	</bean>           

        最後編寫一個測試類:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ioc.lookup.ClerkManager;

public class LookuoDemo {

	public static void main(String[] args) {

		ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		
		ClerkManager clerkManager=(ClerkManager) applicationContext.getBean("clerkManager");
		
		System.out.println("第一次注入的Clerk:"+clerkManager.process());
		
		System.out.println("第二次注入的Clerk:"+clerkManager.process());

	}

}           

        運作測試類,結果如下:

        可以看到,兩次注入的Clerk been是不一樣的,是以達到了我們的目的。