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());