ApplicationContext之getBean方法詳解


我們知道可以通過ApplicationContext的getBean方法來獲取Spring容器中已初始化的bean。getBean一共有以下四種方法原型:

l getBean(String name)

l getBean(Class<T> type)

l getBean(String name,Class<T> type)

l getBean(String name,Object[] args)

下來我們分別來探討以上四種方式獲取bean的區別。

首先本案例項目包結構如下圖:

其中實體類Person定義如下:

public class Person {

private String name;

private int age;

public Person()

{

}

public Person(String name, int age) {

this.name = name;

this.age = 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;

}

@Override

public String toString() {

return "Person [name=" + name + ", age=" + age + "]";

}

}

applicationContext.xml注冊有id為p的bean,配置如下:

<bean id="p" class="com.bean.Person">

<property name="name" value="張三"/>

<property name="age" value="18"/>

</bean>

l getBean(String name)

參數name表示IOC容器中已經實例化的bean的id或者name,且無論是id還是name都要求在IOC容器中是唯一的不能重名。那么這種方法就是通過id或name去查找獲取bean.獲取bean的參考代碼如下:

@Test

public void testPerson()

{

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Person p = (Person) ctx.getBean("p");

System.out.println(p);

}

l getBean(Class<T> type)

參數Class<T> type表示要加載的Bean的類型。如果該類型沒有繼承任何父類(Object類除外)和實現接口的話,那么要求該類型的bean在IOC容器中也必須是唯一的。比如applicationContext.xml配置兩個類型完全一致的bean,且都沒有配置id和name屬性。

<bean class="com.bean.Person">

<property name="name" value="張三"/>

<property name="age" value="18"/>

</bean>

<bean class="com.bean.Person">

<property name="name" value="李四"/>

<property name="age" value="20"/>

</bean>

那么通過com.bean.Person這種類型來查找bean,參考代碼如下:

@Test

public void testPerson()

{

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Person p = ctx.getBean(Person.class);

System.out.println(p);

}

但是由於屬於com.bean.Person的bean在IOC容器中不唯一,所以這里會拋出NoUniqueBeanDefinitionException異常。

由此我們可以總結getBean(String name)和getBean(Class<T> type)的異同點。

相同點:都要求id或者name或者類型在容器中的唯一性。

不同點:getBean(String name)獲得的對象需要類型轉換而getBean(Class<T> type)獲得的對象無需類型轉換。

l getBean(String name,Class<T> type)

這種方式比較適合當類型不唯一時,再通過id或者name來獲取bean

例如applicationContext.xml配置有如下bean:

<bean id="p1" class="com.bean.Person">

<property name="name" value="張三"/>

<property name="age" value="18"/>

</bean>

<bean name="p2" class="com.bean.Person">

<property name="name" value="李四"/>

<property name="age" value="20"/>

</bean>

參考代碼如下:

@Test

public void testPerson()

{

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Person p = ctx.getBean("p2",Person.class);

System.out.println(p);

}

這樣可以獲取到名字叫”李四”的對象。測試結果如下:

l getBean(String name,Object[] args)

這種方式本質還是通過bean的id或者name來獲取bean,通過第二個參數Object[] args可以給bean的屬性賦值,賦值的方式有兩種:構造方法和工廠方法。但是通過這種方式獲取的bean必須把scope屬性設置為prototype,也就是非單例模式。

先在com.factory包下設計有如下的工廠類:

public class PersonFactory {

//靜態工廠注入

public static Person getPersonInstance(String name,int age)throws Exception

{

Person p = (Person)Class.forName("com.bean.Person").newInstance();

Method m = p.getClass().getMethod("setName", java.lang.String.class);

m.invoke(p, name);

m = p.getClass().getMethod("setAge", int.class);

m.invoke(p, age);

return p;

}

}

在applicationContext.xml中配置有如下bean:

<bean name="p3" class="com.bean.Person" scope="prototype"/>

獲取bean的參考代碼如下:

@Test

public void testPerson()

{

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Person p = (Person) ctx.getBean("p3",new Object[]{"王五",35});

System.out.println(p);

}

如果想通過工廠注入屬性,在applicationContext.xml配置如下bean:

<bean name="p3" class="com.factory.PersonFactory" factory-method="getPersonInstance" scope="prototype">

<constructor-arg name="name">

<null/>

</constructor-arg>

<constructor-arg name="age" value="0"/>

</bean>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM