Spring之FactoryBean
FactoryBean
一、官方说明
Interface to be implemented by objects used within a BeanFactory which are themselves factories for individual objects. If a bean implements this interface, it is used as a factory for an object to expose, not directly as a bean instance that will be exposed itself.
由BeanFactory中使用的对象实现的接口,这些对象本身就是单个对象的工厂。如果一个bean实现了这个接口,它将被用作一个要公开的对象的工厂,而不是直接作为一个将要公开的bean实例。
也就是说,FactoryBean本身是一个Bean,但是却是不公开,换句话说,就是不经常使用这个bean,而是使用这个工厂对象产生bean。
NB: A bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in a bean style, but the object exposed for bean references (getObject()) is always the object that it creates.
一个bean实现了FactoryBean接口,不能够做为一个正常的bean。使用FactoryBean可以来定义bean的风格,但是这个bean对象是FactoryBean调用getObject()方法创建出来的对象。
FactoryBeans can support singletons and prototypes, and can either create objects lazily on demand or eagerly on startup. The SmartFactoryBean interface allows for exposing more fine-grained behavioral metadata
FactoryBean可以支持单例和原型bean,并且可以根据需要或在启动时提前创建bean对象。SmartFactoryBean接口允许公开更细粒度的行为元数据
This interface is heavily used within the framework itself, for example for the AOP org.springframework.aop.framework.ProxyFactoryBean or the org.springframework.jndi.JndiObjectFactoryBean. It can be used for custom components as well; however, this is only common for infrastructure code.
该接口在框架本身中大量使用,例如AOP org.springframework.AOP.framework.ProxyFactoryBean或org.springfframework.jndi.JndiObjectFactoryBean。它也可以用于自定义组件;然而,这仅适用于基础结构代码。
The container is only responsible for managing the lifecycle of the FactoryBean instance, not the lifecycle of the objects created by the FactoryBean. Therefore, a destroy method on an exposed bean object (such as java.io.Closeable.close() will not be called automatically. Instead, a FactoryBean should implement DisposableBean and delegate any such close call to the underlying object.
容器只负责管理FactoryBean实例的生命周期,而不是FactoryBean创建的对象的生命周期。因此,不会自动调用公开的bean对象(例如java.io.Closable.close())上的destroy方法。相反,FactoryBean应该实现DisposableBean并将任何此类关闭调用委托给基础对象。
二、FactoryBean组织结构
/**
* 实现此接口的bean不能用作普通bean。此bean暴露的对象是通过getObject()创建的对象,而不是它自身
*/
public interface FactoryBean<T> {
/**
* 返回此工厂管理的对象的实例(可能是共享的或独立的,取决于isSingleton()的返回值)
*/
@Nullable
T getObject() throws Exception;
/**
* 返回此FactoryBean创建的对象类型,
*/
@Nullable
Class<?> getObjectType();
/**
* 该工厂管理的对象是否为单例?
* 如果是(return true),getObject()总是返回同一个共享的实例,该对象会被BeanFactory缓存起来
* 如果是(return false),getObject()返回独立的实例
* 一般情况下返回true
*/
default boolean isSingleton() {
return true;
}
}
说的简单点,FactoryBean是BeanFactory支持的、用来暴露bean实例的接口。
三、FactoryBean使用
public class Car {}
@Component
public class MyFactoryBean implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
return new Car();
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
}
测试类:
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(LiAppCOnfig.class);
applicationContext.refresh();
System.out.println(applicationContext.getBean("myFactoryBean").getClass().getSimpleName());
System.out.println(applicationContext.getBean("&myFactoryBean").getClass().getSimpleName());
打印输出结果:
Car
MyFactoryBean
通过正常的myFactoryBean(beanName)获取得到的是FactoryBean中产生的对象;而通过&myFactoryBean(&beanName)获取得到的是FactoryBean当前类的对象。
四、源码分析
通过源码进行分析
applicationContext.getBean("myFactoryBean")
一开始从spring容器获取名为myFactoryBean的bean,类型确实是:MyFactoryBean,但是后面又经过getObjectForBeanInstance来真正获取我们需要的对象
看下具体的源码:
然后调用具体的方法
那么这里就有一个细节问题:FactoryBean调用getObject()方法产生的对象只走了后置处理方法,没有走初始化前、初始化方法,而是直接走了初始化后方法。
4.1、制造场景
public class Car implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化方法");
}
}
调用测试方法检测,发现控制台打印输出的是:
Car
MyFactoryBean
并没有执行对应的afterPropertiesSet初始化方法。
从这里也证明了,FactoryBean调用getObject()方法产生的对象并不是一个Spring真正意义上的Bean