- 一般情况下,Spring 通过反射机制利用 <bean> 的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 <bean> 中提供大量的配置信息。配置方式的灵活性是受限的。Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。
- 如果有复杂的初始化代码,而不是 (可能) 冗长的 XML,可以用 Java 更好地表达,则可以创建自己的 FactoryBean,在该类中编写复杂的初始化,然后将自定义 FactoryBean 插入容器。
- Spring3.0 开始,FactoryBean 开始支持泛型,即接口声明改为 FactoryBean<T> 的形式。当在 IOC 容器中的 Bean 实现了 FactoryBean 后,通过 getBean (String BeanName) 获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject () 方法返回的对象。要想获取 FactoryBean 的实现类,就要 getBean (&BeanName),在 BeanName 之前加上 &。
- FactoryBean 接口提供了三种方法:
方法 |
说明 |
getObject() |
返回此工厂创建的对象的实例。实例可以共享,具体取决于该工厂是否返回单例或原型。 |
isSingleton() |
如果此 FactoryBean 是单例,则返回 true,否则返回 false。 |
getObjectType() |
返回由 getObject() 方法或 null 返回的对象类型 (如果事先未知)。 |
- FactoryBean 在 IOC 容器的基础上给 Bean 的实现加上了简单工厂模式和装饰者模式,可以在 getObject() 方法中灵活配置
示例
- PersonFactoryBean.java
public class PersonFactoryBean implements FactoryBean<Person> {
private String initStr;
@Override public Person getObject() throws Exception { //获取对应参数 Objects.requireNonNull(initStr); String[] split = initStr.split(","); Person p=new Person(); p.setAge(Integer.parseInt(split[0])); p.setName(split[1]); //其他复杂业务处理 return p; }
@Override public Class<?> getObjectType() { return Person.class; }
public String getInitStr() { return initStr; }
// 接受到逗号分割符设置属性信息 public void setInitStr(String initStr) { this.initStr = initStr; } } |
- application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="cn.lonecloud.spring.example.bo.Person">
<property name="age" value="10"/>
<property name="name" value="xiaoMing"/>
</bean>
<bean id="personFormFactory" class="cn.lonecloud.spring.example.bean.PersonFactoryBean">
<property name="initStr" value="10,init from factory"/>
</bean>
</beans>
- PersonFactoryBeanTest.java
@Test public void test(){ BeanFactory beanFactory = new ClassPathXmlApplicationContext("application.xml"); //获取对应的对象化 Object demo = beanFactory.getBean("person"); System.out.println(demo instanceof Person); System.out.println(demo); //获取从工厂Bean中获取对象 Person demoFromFactory = beanFactory.getBean("personFromFactory", Person.class); System.out.println(demoFromFactory); //获取对应的personFactory Object bean = beanFactory.getBean("&personFromFactory"); System.out.println(bean instanceof PersonFactoryBean); PersonFactoryBean factoryBean = (PersonFactoryBean) bean; System.out.println("初始化参数为:" + factoryBean.getInitStr()); }
|
- 当调用 getBean("personFromFactory") 时,Spring 通过反射机制发现 personFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 PersonFactoryBean#getObject () 方法返回。如果希望获取 PersonFactoryBean 的实例,则需要在使用 getBean (beanName) 方法时在 beanName 前显示的加上 "&" 前缀:如 getBean ("&personFromFactory");