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.../>元素确定参数值