您的位置:首页 > 其它

三、通过 FactoryBean 来配置bean

2017-03-25 00:00 288 查看
一般情况下,Spring 通过反射机制利用 <bean> 的 class 属性指定实现类实例化 Bean ,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在 <bean> 中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。

FactoryBean接口对于 Spring 框架来说占用重要的地位, Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利。从 Spring 3.0 开始, FactoryBean 开始支持泛型,即接口声明改为 FactoryBean<T> 的形式:

public interface FactoryBean<T> {

/**  * Return an instance (possibly shared or independent) of the object  * managed by this factory.  * <p>As with a {@link BeanFactory}, this allows support for both the  * Singleton and Prototype design pattern.  * <p>If this FactoryBean is not fully initialized yet at the time of  * the call (for example because it is involved in a circular reference),  * throw a corresponding {@link FactoryBeanNotInitializedException}.  * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}  * objects. The factory will consider this as normal value to be used; it  * will not throw a FactoryBeanNotInitializedException in this case anymore.  * FactoryBean implementations are encouraged to throw  * FactoryBeanNotInitializedException themselves now, as appropriate.  * @return an instance of the bean (can be {@code null})  * @throws Exception in case of creation errors  * @see FactoryBeanNotInitializedException  */  T getObject() throws Exception;   /**  * Return the type of object that this FactoryBean creates,  * or {@code null} if not known in advance.  * <p>This allows one to check for specific types of beans without  * instantiating objects, for example on autowiring.  * <p>In the case of implementations that are creating a singleton object,  * this method should try to avoid singleton creation as far as possible;  * it should rather estimate the type in advance.  * For prototypes, returning a meaningful type here is advisable too.  * <p>This method can be called <i>before</i> this FactoryBean has  * been fully initialized. It must not rely on state created during  * initialization; of course, it can still use such state if available.  * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return  * {@code null} here. Therefore it is highly recommended to implement  * this method properly, using the current state of the FactoryBean.  * @return the type of object that this FactoryBean creates,  * or {@code null} if not known at the time of the call  * @see ListableBeanFactory#getBeansOfType  */  Class<?> getObjectType();   /**  * Is the object managed by this factory a singleton? That is,  * will {@link #getObject()} always return the same object  * (a reference that can be cached)?  * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,  * the object returned from {@code getObject()} might get cached  * by the owning BeanFactory. Hence, do not return {@code true}  * unless the FactoryBean always exposes the same reference.  * <p>The singleton status of the FactoryBean itself will generally  * be provided by the owning BeanFactory; usually, it has to be  * defined as singleton there.  * <p><b>NOTE:</b> This method returning {@code false} does not  * necessarily indicate that returned objects are independent instances.  * An implementation of the extended {@link SmartFactoryBean} interface  * may explicitly indicate independent instances through its  * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}  * implementations which do not implement this extended interface are  * simply assumed to always return independent instances if the  * {@code isSingleton()} implementation returns {@code false}.  * @return whether the exposed object is a singleton  * @see #getObject()  * @see SmartFactoryBean#isPrototype()  */  boolean isSingleton();  }
在该接口中还定义了以下3 个方法:

T getObject():返回由 FactoryBean 创建的 Bean 实例,如果 isSingleton() 返回 true ,则该实例会放到 Spring 容器中单实例缓存池中;

boolean isSingleton():返回由 FactoryBean 创建的 Bean 实例的作用域是 singleton 还是 prototype ;

Class<T> getObjectType():返回 FactoryBean 创建的 Bean 类型。

当配置文件中<bean> 的 class 属性配置的实现类是 FactoryBean 时,通过 getBean() 方法返回的不是 FactoryBean 本身,而是 FactoryBean#getObject() 方法所返回的对象,相当于 FactoryBean#getObject() 代理了 getBean() 方法。

测试:

package com.xiya.spring.beans.factorybean;  /**  * Created by N3verL4nd on 2017/3/20.  */ public class Car {
private String brand;  private int price;   public Car() {
}

public Car(String brand, int price) {
this.brand = brand;  this.price = price;  }

public String getBrand() {
return brand;  }

public void setBrand(String brand) {
this.brand = brand;  }

public int getPrice() {
return price;  }

public void setPrice(int price) {
this.price = price;  }

@Override  public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';  }
}

package com.xiya.spring.beans.factorybean;  import org.springframework.beans.factory.FactoryBean;  /**  * 通过 FactoryBean 来配置bean  * 需要实现 FactoryBean 接口  * Created by N3verL4nd on 2017/3/20.  */ public class CarFactoryBean implements FactoryBean<Car> {

private String brand;   public void setBrand(String brand) {
this.brand = brand;  }

public void fun() {
System.out.println("CarFactoryBean::fun()");  }

//返回bean的对象  @Override  public Car getObject() throws Exception {
Car car = new Car(brand, 500000);  return car;  }

//返回bean的类型  @Override  public Class<?> getObjectType() {
return Car.class;  }

//返回bean是不是单实例  @Override  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"  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  <!--  通过 FactoryBean 来配置 bean 的实例  class: 指向 FactoryBean 的全类名  property: 配置 FactoryBean 的属性  但实际返回的实例却是 FactoryBean 的 getObject()方法返回的实例。  -->  <bean id="car" class="com.xiya.spring.beans.factorybean.CarFactoryBean">  <property name="brand" value="BMW"/>  </bean> </beans>


输出:
Car{brand='BMW', price=500000}
CarFactoryBean::fun()

Process finished with exit code 0
总之,当需要依赖现有的bean时,可以利用FactoryBean
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: