我们还是遵循WWH原则
What
Why
How
FactoryBean是什么
Spring中BeanFactory应该很熟悉了,IOC的最核心容器之一,IOC的根基。说到FactoryBean就有点不理解了。
在这里记起毕业后的入职第一家公司,架构师就有问到这个面试题。
面试题
面试官:请你说一下BeanFactory和FactoryBean的区别
我:BeanFactory是bean工厂,Spring IOC的核心容器;而FactoryBean则是工厂bean。
面试官:FactoryBean究竟是个什么样的工厂bean?
我:这个不太懂。
看源码的好奇心
时过七年,依然不知道FactoryBean究竟是什么样的工厂bean?
由于看Spring IOC源码,就是getBean()加载bean就有判断该bean是否为FactoryBean,这里勾起我面试的回忆,以及自己好奇心,那就去看看吧。
Spring的bean分为两种,一种就是普通的bean,另一种就是工厂bean(FactoryBean)。
FactoryBean跟普通bean区别在于,其返回的对象不是指定类的实例,而是该FactoryBean的getObject方法所返回的对象。
为什么使用FactoryBean
FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。
FactoryBean如何实战
简单案例
1.Car实体类
package com.feiniu.springframework.factoryBean;
public class Car {
private int maxSpeed;
private String brand;
private double price;
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
2.用来获取Car的CarFactoryBean,必须继承FactoryBean接口
package com.feiniu.springframework.factoryBean;
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car>{
private String carInfo;
public String getCarInfo() {
return carInfo;
}
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setMaxSpeed(Integer.parseInt(infos[0]));
car.setBrand(infos[1]);
car.setPrice(Double.parseDouble(infos[2]));
return car;
}
@Override
public Class<Car> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
3.配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"
default-autowire="byName">
<bean id="car" class="com.feiniu.springframework.factoryBean.CarFactoryBean" >
<property name="carInfo" value="400,兰博基尼,2000000.00" />
</bean>
</beans>
4.测试类
package com.feiniu.springframework.factoryBean;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestCar {
public static void main(String[] args) throws Exception {
ApplicationContext context = new FileSystemXmlApplicationContext(
"applicationContext.xml");
Object car = context.getBean("car");
System.out.println("Car is " + (car instanceof Car));
System.out.println(((Car)car).getBrand());
Object carFactoryBean = context.getBean("&car");
System.out.println("carFactoryBean is " + (carFactoryBean instanceof CarFactoryBean));
System.out.println(((CarFactoryBean)carFactoryBean).getObject());
}
}
控制台输出
Car is true
兰博基尼
carFactoryBean is true
com.feiniu.springframework.factoryBean.Car@26a549a8
前面我们在看IOC源码的时候,发现即使我们已经创建出来了对象的实例,还是要走一个方法再去处理下,这里就是对FactoryBean的处理,因为它可以产生对象,所以你getBean的时候取到的不是它本身,而是通过它生成的产品。【如果要取它本身,getBean(&+beanName)】
我们先来回忆下IOC源码中那个处理FactoryBean的简略代码
代码1.1:AbstractBeanFactory类的doGetBean方法
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
无论是直接取单例的bean,还是创建单例、多例、自定义生命周期的bean,都会执行下面方法:
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
这个方法,我们现在就来看看这里到底是做了什么
代码1.2:AbstractBeanFactory类的getObjectForBeanInstance方法
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 如果指定名称是FactoryBean的解引用,且bean对象不是FactoryBean,抛出异常
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 如果Bean实例不是FactoryBean,或者指定名称是FactoryBean的解引用,也就是普通的bean调用,则直接返回当前的Bean实例
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 处理对FactoryBean的调用
Object object = null;
if (mbd == null) {
// 从Bean工厂缓存中获取给定名称的实例对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// 如果bean是单例模式,则缓存
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
来梳理一下获取bean的逻辑
dereference是间接引用的意思
public static boolean isFactoryDereference(String name) {
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
String FACTORY_BEAN_PREFIX = "&";
判断一个bean是普通bean还是FactoryBean,根据对象beanInstance和对象名称name
// 异常
if (name为间接引用 && beanInstance 不是 FactoryBean) {
异常抛出
}
// 普通bean
if (beanInstance 不是 FactoryBean || name为间接引用) {
return beanInstance;
}
// 其他的就是factoryBean