FactoryBean

Exisi 2022-06-28 07:40:05
Categories: Tags:
  • 一般情况下,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");