大多数情况下,beanfactory直接通过new 关键字调用构造器来创建Bean实例,而class属性值定了Bean实例的实现类。因此,<bean.../>元素必须制定Bean实例的class属性,但这不是实例化Bean的唯一方法。
创建Bean通常有如下方法:
1)调用构造器创建Bean实例。
第一种情况:使用构造器创建Bean实例
使用构造器创建Bean实例是最常见的情况,如果采用设置注入的方式,要求该类提供无参数的构造器。这种情况下,class元素是必须的,class属性的值就是Bean实例的实现类。
beanfactory将使用默认构造器来创建Bean实例,该实例是一个默认实例,Spring对Bean实例的所有属性执行默认初始化,即所有基本类型的值初始化为0或FALSE;所有引用类型的值初始化为null。
接下来,beanfactory会根据配置文件决定依赖关系,先实例化被依赖的Bean实例,然后为Bean注入依赖关系,最后将一个完成的Bean实例返回给程序,该Bean实例的所有属性,已经由Spring容器完成了初始化。
调用Bean的接口和实现类:
package org.crazyit.app.service; public interface Person { //定义一个使用斧子的方法 public void useAxe(); }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class Chinese implements Person { private Axe axe; //设置注入所需要的Setter方法 public void setAxe(Axe axe) { this.axe = axe; } //默认的构造器 public Chinese() { System.out.println("Spring实例化主调Bean:Chinese实例。。。"); } //实现Person接口的useAxe方法 public void useAxe() { //调用axe的chop()方法 //表明Person对象依赖于axe对象 System.out.println(axe.chop()); } }
下面给出的是Person接口依赖Bean的接口和实现类。
package org.crazyit.app.service; public interface Axe { //Axe接口里有个砍的方法 public String chop(); }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class SteelAxe implements Axe { //默认的构造器 public SteelAxe(){ System.out.println("Spring实例化依赖Bean:SteelAxe实例。。。."); } //实现Axe接口的chop方法 public String chop() { return "钢斧砍柴真快"; } }
<?xml version="1.0" encoding="GBK"?> <!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置chinese实例,其实现类是Chinese --> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese"> <!-- 使用property元素用来指定需要容器注入的属性,axe属性需要容器注入 --> <property name="axe" ref="steelAxe"></property> </bean> <!-- 配置stoneAxe实例,其实现类是StoneAxe --> <bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/> <!-- 配置steelAxe实例,其实现类是SteelAxe --> <bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/> <context:annotation-config/> </beans>
测试程序:
package lee; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.crazyit.app.service.*; import org.junit.Test; public class BeanTest { @Test public void testBean() throws Exception { //创建Spring容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); //获取chinese 实例 Person p = ctx.getBean("chinese",Person.class); //调用useAxe()方法 p.useAxe(); } }
上面的程序获得一个Person对象, Spring会先创建Person所以来的Bean实例,在创建一个默认的Person实例,燃火将Person所以来的Bean实例注入Person实例。结果如下:
使用静态工厂方法创建Bean实例是,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。Spring需要知道由哪个静态工程方法创建Bean实例。
除此之外,还需要使用factory-method属性指定静态工厂方法名,Spring将调用静态工程方法,来放回一个Bean实例,一旦获得了指定Bean实例,Spring后面的处理步骤与采用普通方法创建Bean实例则完全一样。
下面的Bean要由factory-method指定的静态工厂方法来创建,所以这个<bean.../>元素的class属性指定的是静态工程类,factory-method指定的工厂方法必须是静态的。由此可见,采用静态工程方法创建Bean实例时,<bean.../>元素需要指定如下两个属性。
class:该属性的值为静态工厂类名。
factory-method:该属性指定静态工厂方法来生产Bean实例。
如果静态工厂方法需要参数,则使用<constructor-arg.../>元素传入。
下面先定义一个接口,静态工厂方法将会产生两个实现类的实例。
package org.crazyit.app.service; public interface Being { //接口定义testBeing方法 public void testBeing(); }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class Cat implements Being { private String msg; //依赖注入时候必须的setter方法 public void setMsg(String msg) { this.msg = msg; } //实现接口必须实现的testBeing方法 public void testBeing() { System.out.println(msg + " 猫喜欢吃老鼠"); } }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class Dog implements Being { private String msg; //依赖注入时候必须的setter方法 public void setMsg(String msg) { this.msg = msg; } //实现接口必须实现的testBeing方法 public void testBeing() { System.out.println(msg + " 狗爱啃骨头"); } }
下面的BeingFactory工厂包含了一个getBeing静态方法,该静态方法用于返回一个Being实例,这是典型的静态工厂的设计模式。
package org.crazyit.app.factory; import org.crazyit.app.service.impl.*; import org.crazyit.app.service.*; public class BeingFactory { /** * 获取Being实例的静态工厂方法 * @param arg 决定返回哪个Being实例的参数 */ public static Being getBeing(String arg) { //调用此静态方法的参数为dog,则返回Dog实例 if (arg.equalsIgnoreCase("dog")) { return new Dog(); } //否则返回Cat实例 else { return new Cat(); } } }
上面的BeingFactory类是一个静态工厂类,该类的getBeing()方法是一个静态工厂方法,该方法根据传入的参数决定返回Cat对象还是Dog对象。
如果需要指定Spring让BeingFactory来生产Being对象,则应该按如下静态工厂方法的方式来配置Dog、Cat Bean。
<?xml version="1.0" encoding="GBK"?> <!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 --> <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-3.0.xsd"> <!-- 配置BeingFactory的getBeing方法产生dog Bean --> <bean id="dog" class="org.crazyit.app.factory.BeingFactory" factory-method="getBeing"> <!-- 配置静态工厂方法的参数 --> <constructor-arg value="dog"/> <!-- property配置普通依赖注入属性 --> <property name="msg" value="我是狗"/> </bean> <!-- 配置BeingFactory的getBeing方法产生dog Bean --> <bean id="cat" class="org.crazyit.app.factory.BeingFactory" factory-method="getBeing"> <!-- 配置静态工厂方法的参数 --> <constructor-arg value="cat"/> <!-- property配置普通依赖注入属性 --> <property name="msg" value="我是猫"/> </bean> </beans>
主程序获取Spring容器的cat、dog两个Bean实例的方法依然无须改变,只需要调用Spring容器的getBean()方法即可。
package lee; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.crazyit.app.service.*; import org.junit.Test; public class BeanTest { @Test public void testBean() throws Exception { //以类加载路径下的配置文件创建ClassPathResource实例 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); Being b1 = ctx.getBean("dog",Being.class); b1.testBeing(); Being b2 = ctx.getBean("cat",Being.class); b2.testBeing(); } }
使用静态工厂方法创建实例时必须提供工厂类,工厂类包含产生实例的静态工厂方法。通过静态工厂方法创建实例需要对配置文件进行如下改变:
class属性的值不在是Bean实例的实现类,而是生成Bean实例的静态工厂类。
使用factory-method属性指定生产Bean实例的静态工厂方法
如果静态工厂需要参数,则使用<constructor-arg.../>元素指定静态工厂方法的参数。
当我们指定Spring使用静态工厂方法创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工程类的静态工厂方法,将静态工厂方法的返回值作为Bean实例。在这个过程中,Spring不在负责创建Bean实例,Bean实例是由用户提供的静态工厂类负责创建的。
当静态工厂方法创建了Bean实例后,Spring依然可以管理Bean实例的依赖关闭,包括为其注入所需要的依赖关系,管理生命周期等。
实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需要使用工厂类即可,调用实例工厂方法则需要使用工厂实例。所以配置实例工厂方法与配置静态工厂方法基本相似,只有一点区别:配置静态工厂方法指定静态工厂类,配置实例工厂方法则指定工厂实例。
package org.crazyit.app.service; public interface Person { //定义一个打招呼的方法 public String sayHello(String name); //定义一个告别的方法 public String sayGoodBye(String name); }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class Chinese implements Person { //实现Person接口必须实现如下两个方法 public String sayHello(String name) { return name + ",您好"; } public String sayGoodBye(String name) { return name + ",下次再见"; } }
package org.crazyit.app.service.impl; import org.crazyit.app.service.*; public class American implements Person { //实现Person接口必须实现如下两个方法 public String sayHello(String name) { return name + ",Hello!"; } public String sayGoodBye(String name) { return name + ",Good Bye!"; } }
package org.crazyit.app.factory; import org.crazyit.app.service.*; import org.crazyit.app.service.impl.*; public class PersonFactory { /** * 获得Person实例的实例工厂方法 * @param ethnic 决定返回哪个Person实例的参数 * @return 返回Person实例 */ public Person getPerson(String ethnic) { if (ethnic.equalsIgnoreCase("chin")) { return new Chinese(); } else { return new American(); } } }
<?xml version="1.0" encoding="GBK"?> <!-- Spring配置文件的根元素,使用spring-beans-3.0.xsd语义约束 --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置工厂Bean,该Bean负责产生其他Bean实例 --> <bean id="personFactory" class="org.crazyit.app.factory.PersonFactory"/> <!-- 采用实例工厂创建Bean实例,factory-bean指定工厂Bean的id属性 factory-method属性指定工厂Bean的实例工厂方法 --> <bean id="chinese" factory-bean="personFactory" factory-method="getPerson"> <!-- 调用工厂方法时,传入的参数通过constructor-arg元素指定 --> <constructor-arg value="chin"/> </bean> <bean id="american" factory-bean="personFactory" factory-method="getPerson"> <constructor-arg value="ame"/> </bean> <context:annotation-config/> </beans>
测试程序:
package lee; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.crazyit.app.service.*; import org.junit.Test; public class BeanTest { @Test public void testBean() throws Exception { //以类加载路径下的配置文件创建ClassPathResource实例 ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml"); Person p1 = ctx.getBean("chinese",Person.class); System.out.println(p1.sayHello("Mary")); System.out.println(p1.sayGoodBye("Mary")); Person p2 = ctx.getBean("american",Person.class); System.out.println(p2.sayHello("Jack")); System.out.println(p2.sayGoodBye("Jack")); } }
测试结果:
调用实例工厂方法创建Bean和调用静态工厂方法创建Bean的用法基本相似。区别如下:
1)调用实例工厂方法创建Bean,必须将实例工厂配置成Bean实例。而静态工厂方法创建Bean,则无需配置工厂Bean
2)调用实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean。确定工厂的Bean。而静态工厂方法创建Bean,则使用class元素确定静态工厂类。
3)都需要使用factory-method属性指定产生Bean实例的工厂方法
4)工厂方法如果需要参数,都使用<constructor-arg.../>元素指定参数值。
5)其它依赖注入属性,都是用<proterty..../>元素确定参数值。
原文链接:https://www.f2er.com/javaschema/285230.html