1. 程式人生 > >Spring之建立Bean的方式

Spring之建立Bean的方式

Bean有別於傳統的JavaBean,任何應用元件都可以作為Bean,接下來講述的是Spring中建立Bean的方式。

1.呼叫構造器建立Bean

使用構造器來建立Bean是最常見的情況,如果是構造注入,則通過配置建構函式來實現建立Bean,如果是設值注入,Spring底層會呼叫Bean類的無引數構造器來建立例項。以下講述的是設值注入。 以下是需要的介面
package impl;


public interface Axe {
	public String chop();

}
package impl;

public interface Creature {

	public void useTool();
}
package impl;

public interface Metal {
	public String make();

}
以下是三個介面相應的實現類:

package impl.handle;

import impl.Axe;

public class StealAxe implements Axe {

	@Override
	public String chop() {
		// TODO Auto-generated method stub
		return "使用斧頭砍柴";
	}

}
package impl.handle;

import impl.Axe;
import impl.Creature;
import impl.Metal;
public class Person implements Creature
{
	private Axe axe;
	private Metal metal;
	// 設值注入所需的setter方法
	public void setMetal(Metal metal)
	{
		this.metal=metal;
		
	}
	public void setAxe(Axe axe)
	{
		this.axe=axe;
	}
	public void useTool()
	{
		System.out.println("我打算去砍點柴火!");
		// 呼叫axe的chop()方法,
		// 表明Person物件依賴於axe物件
		System.out.println(metal.make());
		System.out.println(axe.chop());
	}
}
package impl.handle;

import impl.Metal;

public class Steal implements Metal {
	public String make()
	{
		return "使用鐵做斧頭";
	}

}
根據需要的功能,編寫工具類
package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import impl.handle.*;
import impl.*
;public class BeanTest
{
	public static void main(String[] args)throws Exception
	{
		// 以類載入路徑下的beans.xml檔案建立Spring容器
		ApplicationContext ctx = new
			ClassPathXmlApplicationContext("beans.xml");    // ①
		// 載入類的時候需要載入介面,從而真正實現面向介面程式設計。
		Creature c=(Creature)ctx.getBean("person", Creature.class);
		c.useTool();
	}
}
然後對Beans.xml檔案進行配置
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<!-- 配置名為person的Bean,其實現類是org.crazyit.app.service.Person類 -->
	<bean id="person" class="impl.handle.Person">
		<property name="metal" ref="steal"/>
		<property name="axe" ref="stealAxe"/>
	</bean>
	<bean id="steal" class="impl.handle.Steal"/>
	<bean id="stealAxe" class="impl.handle.StealAxe"/>
</beans>

以上是設值注入,所以使用的是Spring底層呼叫Bean類的無引數構造器來建立例項的。這裡的Bean類是指Steal類和StealAxe類。

2.呼叫靜態工廠方法建立Bean

所謂靜態工廠方法就是建立一個工廠類,工廠類有個靜態工廠方法,讓產品的例項化在工廠類的靜態工廠方法中進行,讓整個過程都面向介面程式設計。並且在配置beans.xml檔案略有不同。通過以下例子進行詳細講述。 首先先定義一個介面,該介面的例項就是在靜態工廠方法中生產的。
package handle;

public interface Being {
	public void testBeing();

}
以下兩個類Dog類和Cat類便是以上介面的實現類。
package handle.impl;

import handle.Being;

public class Dog implements Being {
	
	private String msg;
	public void setMsg(String msg)
	{
		this.msg=msg;
	}
	//實現介面中的testBeing()方法
	@Override
	public void testBeing() {
		// TODO Auto-generated method stub
		System.out.println(msg+",狗愛啃骨頭");

	}

}
package handle.impl;

import handle.Being;

public class Cat implements Being {

	private String msg;
	public void setMsg(String msg)
	{
		this.msg=msg;
	}
	@Override
	public void testBeing() {
		// TODO Auto-generated method stub
		System.out.println(msg+",貓喜歡吃老鼠");

	}

}

相應的類都準備就緒,產品的原料都到了,就等著工廠進行集中生產,於是我們應當建立一個工廠類,然後在工廠類中建立一個靜態工廠方法,將所有的類進行相應的例項化。
package factory;
import handle.*;
import handle.impl.*;
public class BeingFactory {
	//返回Being例項的靜態工廠方法
	public static Being getBeing(String arg)
	{
		//呼叫次靜態方法的引數是dog,則返回Dog例項
		if(arg.equalsIgnoreCase("dog"))
		{
			return new Dog();
		}
		else
		{
			return new Cat();
		}
	}

}
以上便是一個工廠類BeingFactory,而工廠類有個靜態方法是getBeing(String arg),而arg是傳入的引數,相當於外界需要什麼類的例項,則工廠方法就例項化什麼類。 以下是beans.xml的配置內容:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<bean id="dog" class="factory.BeingFactory" factory-method="getBeing">
		<constructor-arg value="dog"/>
		<property name="msg" value="我是狗"/>
	</bean>
	<bean id="cat" class="factory.BeingFactory" factory-method="getBeing">
		<constructor-arg value="cat"/>
		<property name="msg" value="我是貓"/>
	</bean>
</beans>
可以看出<bean.../>子元素中id還是指例項名,作為標識作用,而class與構造器建立Bean的有所不同,構造器建立Bean的class指的是id對應的需要例項的類名,而靜態工廠方法建立Bean中的class是工廠類的類名(包含包路徑),另外不同的是還多了factory-method元素,是指工廠類中的靜態工廠方法名,如上便是getBeing。而靜態方法需要的相應的引數,則使用<constructor-arg.../>傳入,而傳入的引數還需要引數,則由<property.../>元素傳入。 接下來是建立工具類:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import handle.*;
public class SpringTest {

	public static void main(String[] args)
	{
		// 以類載入路徑下的beans.xml檔案建立Spring容器
		ApplicationContext ctx = new
			ClassPathXmlApplicationContext("beans.xml"); 
		Being b1=ctx.getBean("dog", Being.class);
		b1.testBeing();
		Being b2=ctx.getBean("cat", Being.class);
		b2.testBeing();
	}
}
執行工具類之後,得到如下結果:
我是狗,狗愛啃骨頭
我是貓,貓喜歡吃老鼠
以上便是靜態工廠方法建立Bean的示例。與構造器建立Bean最大的不同便是使用了工廠方法集中例項化,還有就是配置中<bean.../>元素中的class的不同。

3.呼叫例項工廠方法建立Bean

呼叫例項工廠方法與呼叫靜態工廠方法類似,只是工廠類中的工廠方法有無static之分,以及配置上內容稍有差異,為便於區分,仍然使用呼叫靜態工廠方法的示例。
先是產品介面:
package handle;

public interface Being {
	public void testBeing();

}
然後相應的產品類:
package handle.impl;

import handle.Being;

public class Dog implements Being {
	
	private String msg;
	public void setMsg(String msg)
	{
		this.msg=msg;
	}
	//實現介面中的testBeing()方法
	@Override
	public void testBeing() {
		// TODO Auto-generated method stub
		System.out.println(msg+",狗愛啃骨頭");

	}

}
package handle.impl;

import handle.Being;

public class Cat implements Being {

	private String msg;
	public void setMsg(String msg)
	{
		this.msg=msg;
	}
	@Override
	public void testBeing() {
		// TODO Auto-generated method stub
		System.out.println(msg+",貓喜歡吃老鼠");

	}

}
建立工廠類,可以看到工廠類中的工廠方法沒有static。
package factory;
import handle.*;
import handle.impl.*;
public class BeingFactory {
	//返回Being例項的靜態工廠方法
	public Being getBeing(String arg)
	{
		//呼叫次靜態方法的引數是dog,則返回Dog例項
		if(arg.equalsIgnoreCase("dog"))
		{
			return new Dog();
		}
		else
		{
			return new Cat();
		}
	}

}
以下是beans.xml的配置:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<!-- 配置名為beingFactory的工廠類Bean,其實現類是factory.beingFactory類 -->
	<bean id="beingFactory" class="factory.BeingFactory"/>
	<!-- 下面配置驅動Spring呼叫beingFactory Bean的getBeing()方法來建立Bean,該Bean元素包含地constructor-arg元素用於為工廠方法指定引數
	BeingFactory bf=container.get("beingFactory");//container代表Spring容器
	dog=bf.getBeing("dog");-->
	<bean id="dog" factory-bean="beingFactory" factory-method="getBeing">
		<constructor-arg value="dog"/>
		<property name="msg" value="我是狗"/>
	</bean>
	<bean id="cat" factory-bean="beingFactory" factory-method="getBeing">
		<constructor-arg value="cat"/>
		<property name="msg" value="我是貓"/>
	</bean>
</beans>
從以上配置內容可以看出,先對工廠類進行配置,工廠類的配置跟呼叫構造器的配置類似,主要是id與class,然後進行配置產品例項,id仍然是產品名,但是沒有class,而是用factory-bean取代,factory-bean就是前面已經配置好的工廠類的id,factory-method則是工廠方法,其餘都同調用靜態工廠方法。主要區別在於先進行工廠類的Bean配置,然後配置產品Bean例項時,class用factory-bean取代。 最後建立工具類:
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import handle.*;
public class SpringTest {

	public static void main(String[] args)
	{
		// 以類載入路徑下的beans.xml檔案建立Spring容器
		ApplicationContext ctx = new
			ClassPathXmlApplicationContext("beans.xml"); 
		Being b1=ctx.getBean("dog", Being.class);
		b1.testBeing();
		Being b2=ctx.getBean("cat", Being.class);
		b2.testBeing();
	}
}
執行工具類,得到如下結果:
我是狗,狗愛啃骨頭
我是貓,貓喜歡吃老鼠
綜上所述,建立Bean的三種方式,首先使用工廠方法建立Bean與呼叫構造器建立Bean的區別在於:1.前者使用了工廠方法便於集中管理,而後者只是將Bean例項作為引數傳入其它類。2.配置beans.xml的內容略有不同。 而呼叫靜態方法建立Bean與呼叫例項工廠方法建立Bean的區別: 1.配置例項工廠方法建立Bean,必須將例項工廠配置成Bean例項,而配置靜態工廠方法建立Bean,無須配置工廠Bean 2.配置例項工廠方法建立Bean,必須使用factory-bean屬性確定工廠Bean,而配置靜態工廠方法建立Bean,使用class元素確定靜態工廠類。 相同之處: 1.都需要factory-method屬性確定Bean例項的工廠方法 2.工廠方法需要引數,都使用<constructor-arg.../>元素指定引數值 3.普通的設值注入,都使用<property.../>元素確定引數值