FactoryBean通常是用来创建比较复杂的bean,一般的bean直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean和复杂的逻辑,用xml配置比较困难,这时可以考虑用的FactoryBean。
FactoryBean的接口
package org.springframework.beans.factory;
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
我们先看一下 FactoryBean 的应用案例 然后在对其进行分析和讲解
很多开源项目在集成Spring时都使用到FactoryBean,比如MyBatis提供mybatis-spring项目中的org.mybatis.spring.SqlSessionFactoryBean
bean id="tradeSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="trade" />
<property name="mapperLocations" value="classpath*:mapper/trade/*Mapper.xml" />
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="typeAliasesPackage" value="com.bytebeats.mybatis3.domain.trade" />
</bean>
org.mybatis.spring.SqlSessionFactoryBean
如下:
package org.mybatis.spring;
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
......
}
另外,阿里开源的分布式服务框架Dubbo中的Consumer也使用到了FactoryBean:
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
}
下面我们进行一个案例 来说明一下 FactoryBean的使用
1 声明一个Person类
package com.lqp.test.day02;
public class Person {
public void say() {
System.out.println("我 》。。");
}
}
2 声明一个工厂类 继承 FactoryBean 的方法
package com.lqp.test.day02;
import org.springframework.beans.factory.FactoryBean;
public class PersonFactory implements FactoryBean<Person>{
@Override
public Person getObject() throws Exception {
return new Person(); // 返回一个对象
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Person.class; //返回一个类的类型
}
@Override
public boolean isSingleton() {
return true; //是否是单例
}
}
3 声明一个配置类 对PersonFactory 类 进行配置
package com.lqp.test.day02;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConfigTest {
//为PersonFactory 注册
//注意 这里的bean 存放的不是PersonFactory对象 而是 他里面的person对象
@Bean
public PersonFactory personFactory() {
return new PersonFactory();
}
}
4 测试类
package com.lqp.test.day02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestConfig {
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigTest.class);
Person bean = (Person)context.getBean("personFactory"); //获得的是 Person对象
System.out.println(bean.getClass().getName()); //com.lqp.test.day02.Person
bean.say(); //我 》。。
//因为PersonFactory 实现了 FactoryBean 的接口 所以他将不是普通的bean
//如果将要获取它 那么就需要在 相应的 实现bean的name 前面加一个 & 符号
Object bean2 = context.getBean("&personFactory") ;
String name = bean2.getClass().getName();
System.out.println(name); //com.lqp.test.day02.PersonFactory
}
}
源码注释
由{@link BeanFactory}中使用的对象实现的接口
这些都是工厂。如果bean实现了这个接口,
它被用作公开的对象的工厂,而不是直接作为bean
将暴露自己的实例。
<p> <b>注意:实现此接口的bean不能用作普通bean。</ b> FactoryBean是以bean样式定义的,但是为bean引用公开的对象({@link #getObject()始终是它创建的对象。
<p> FactoryBeans可以支持单例和原型,并且可以
或者根据需要懒洋洋地创建对象,或者在启动时急切地创建对象。
{@link SmartFactoryBean}接口允许公开
更精细的行为元数据。
<p>此接口在框架内部大量使用,用于
AOP的例子{@link org.springframework.aop.framework.ProxyFactoryBean}
或{@link org.springframework.jndi.JndiObjectFactoryBean}。
它也可以用于应用程序组件;然而,
这在基础设施代码之外并不常见。
<P> <b>注意:</ b>的
FactoryBean对象参与包含
BeanFactory的bean创建同步。通常没有
除了懒惰之外,还需要内部同步
在FactoryBean本身(或类似)中初始化。