一般情况下,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

最新文章

  1. vue-router(2.0)
  2. Graphviz绘制百家争鸣图
  3. OSD磁盘日常监控
  4. 迭代加深搜索 codevs 2541 幂运算
  5. Web开发——Tomcat的配置
  6. CSS浮动讲解好文章推荐
  7. 推荐一款JavaScript日历控件:kimsoft-jscalendar
  8. 调色板类QPalette——包含了Qt窗口不见的颜色组(collor group),和Windows右键属性外观非常类似
  9. JS 获取上传文件的内容
  10. vtop工具使用分析
  11. Linux 系统管理
  12. 关于Springboot打包错误的问题 | Failed to execute goal org.springframework.boot:spring-boot-maven-plugin
  13. 通过T4模板实现代码自动生成
  14. css 1) calc() 函数的使用. 2)box-sizing:border-box
  15. Ural 2040. Palindromes and Super Abilities 2 回文自动机
  16. Inversion of Control Containers and the Dependency Injection pattern
  17. Javascript中Date对象的格式化
  18. P4777 【模板】扩展中国剩余定理(EXCRT)&amp;&amp; EXCRT
  19. 【AtCoder】AGC011 C - Squared Graph
  20. [AngularJS] Angular1.3 ngAria - 1

热门文章

  1. UML类图基础
  2. shell正则表达式和cut命令
  3. 常用加密算法-Delphi XE 10.3.3
  4. P2871 [USACO07DEC]手链Charm Bracelet(01背包模板)
  5. 关于Element对话框组件Dialog在使用时的一些问题及解决办法
  6. Android 平台JS调试技术
  7. Spring Boot2 系列教程(二十) | SpringBoot 是如何实现日志的?
  8. Spring Boot2 系列教程 (四) | 集成 Swagger2 构建强大的 RESTful API 文档
  9. 自学 JAVA 的几点建议
  10. cogs 495. 滑动窗口 单调队列