Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。
工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。
使用场景:
1、通过外部对类是否是单例进行控制,该类自己无法感知;
2、对类的创建之前进行初始化的操作,在afterPropertiesSet()中完成。
实例一:
基础类:Student.java
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
工厂类:StuFactory.java
public class StuFactory implements FactoryBean, InitializingBean {
public void afterPropertiesSet() throws Exception {
System.out.println("student class initialized.");
}
public Object getObject() throws Exception {
return new Student();
}
public Class getObjectType() {
return Student.class;
}
public boolean isSingleton() {
return true;
}
}
注入到配置文件中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
<bean id="stuFactory" class="com.alibaba.spring.StuFactory">
</bean>
</beans>
测试:
public class StuFactoryTest {
@Test
public void test1() throws Throwable {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stuFactory1 = (Student) context.getBean("stuFactory");
Student stuFactory2 = (Student) context.getBean("stuFactory");
System.out.println(stuFactory1 == stuFactory2);
}
}
测试结果:
student class initialized.
true
【注意】
1、返回的是getObject()中说明的类型,而不是创建工厂的类型,与普通的javabean不一样
2、创建出来的对象是否属于单例由isSingleton中的返回决定。
实例二:
FactoryBeanDemo.java
public class FactoryBeanDemo implements FactoryBean {
private String name;
public void setName(String name) {
this.name = name;
}
public Object getObject() throws Exception {
if ("date".equals(name))
return new Date();
else
return new String("这是一个字符串!");
}
public Class getObjectType() {
return "date".equals(name) ? Date.class : String.class;
}
public boolean isSingleton() {
return false;
}
}
配置文件:
<bean name="myFactoryBean" class="com.alibaba.spring.FactoryBeanDemo" />
<bean name="myFactoryBean1" class="com.alibaba.spring.FactoryBeanDemo">
<property name="name" value="date"></property>
</bean>
测试:
Resource res = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(res);
System.out.println(factory.getBean("myFactoryBean").getClass());
System.out.println(factory.getBean("myFactoryBean1").getClass());
System.out.println("=====================================");
System.out.println(factory.getBean("&myFactoryBean").getClass());
System.out.println(factory.getBean("&myFactoryBean1").getClass());
由此可见,通过使用FactoryBean,我们可以得到不同类型的对象实例。这也就是我们在AOP中通过设置calss为ProxyFactoryBean可以返回不同类型的业务对象的原理。在实际应用中若能灵活使用FactoryBean,则可以给应用程序增加很多的魔幻功能。
测试结果:
class java.lang.String
class java.util.Date
=====================================
class com.alibaba.spring.FactoryBeanDemo
class com.alibaba.spring.FactoryBeanDemo
一个小窍门:
FactoryBean还藏有一个技巧,也就是在我们实际需要返回FactoryBean实例时,应该怎么办。也就是我们在应用程序中需要通过容器得到一个FactoryBean。此时,需要使用特殊的方式,即在bean的名称前加上一个特殊符号“&”即可。即:System.out.println(factory.getBean("&myFactoryBean").getClass());