Spring IOC(四)FactoryBean

Spring IOC(四)FactoryBean

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

Spring IOC(四)FactoryBean_第1张图片

一般情况下,Spring 通过反射机制利用 bean 的 class 属性指定实现类来实例化 bean。在某些情况下特别是整合第三方包时,实例化 bean 过程比较复杂,如果按照传统的方式,则需要在 XML 中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 bean 的逻辑。

public interface FactoryBean {
    T getObject() throws Exception;
    Class getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

在该接口中还定义了以下3个方法:

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

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

(3) Class getObjectType():返回 FactoryBean 创建的 bean 类型。

一、Spring 中使用 FactoryBean

在如下的 Bean 通过 FactoryBean 注入

public class CarFactoryBean implements FactoryBean {
    private String carInfo;

    @Override
    public Car getObject() throws Exception {
        String[]infos = carInfo.split(",");
        return Car car=new Car(infos[0], Integer.parseInt(infos[1]), Double.parseDouble(infos[2]));
    }

    @Override
    public Class getObjectType() {
        return null;
    }
}

public class Car {
    private String brand;
    private int maxSpeed;
    private Double price;
    // get/set
}  

有了这个 CarFactoryBean 后,就可以在配置文件中使用下面这种自定义的配置方式配置了


    

当调用 getBean("car") 时,Spring 通过反射机制发现 CarFactoryBean 实现了 FactoryBean 的接口,这时 Spring 容器就调用接口方法 CarFactoryBean#getObject() 方法返回。如果希望获取 CarFactoryBean 的实例,则需要在使用 getBean(beanName) 方法时在 beanName 前显示的加上 & 前缀,例如 getBean("&car")

二、FactoryBeanRegistrySupport

FactoryBeanRegistrySupport 提供了对 FactoryBean 的支持,最重要的方法是 getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess),这个方法通过 factoryBean 获取 bean 对象。

(1) 属性

// 缓存 beanName -> FactoryBean 的集合
private final Map factoryBeanObjectCache = new ConcurrentHashMap<>(16);

(2) getObjectFromFactoryBean 注册

getObjectFromFactoryBean 负责从 FactoryBean#getObject() 中获取真正想要的 bean 对象,而不是 FactoryBean 本身。AbstractBeanFactory#getObjectForBeanInstance 获取 bean 之前会判断是不是 FactoryBean。

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                // TODO ? 什么意思,循环引用?
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    if (shouldPostProcess) {
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
                            // 外面 BeanPostProcessor 作用在 factory 上,没有作用在实际想要的实例上,这边补一个
                            // 也就是说 BeanPostProcessor 的 postProcessBeforeInitialization 不会作用在 FactoryBean 上
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable ex) {
                            throw new BeanCreationException(beanName", ex);
                        } finally {
                            afterSingletonCreation(beanName);
                        }
                    }
                    if (containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    } else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

// 调用 FactoryBean#getObject() 创建 bean
private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName)
        throws BeanCreationException {
    Object object = factory.getObject();

    if (object == null) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

// 子类重写
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
    return object;
}

(3) 查找与删除

protected Object getCachedObjectForFactoryBean(String beanName) {
    return this.factoryBeanObjectCache.get(beanName);
}

@Override
protected void removeSingleton(String beanName) {
    synchronized (getSingletonMutex()) {
        super.removeSingleton(beanName);
        this.factoryBeanObjectCache.remove(beanName);
    }
}
@Override
protected void clearSingletonCache() {
    synchronized (getSingletonMutex()) {
        super.clearSingletonCache();
        this.factoryBeanObjectCache.clear();
    }
}

(4) 其它方法

protected Class getTypeForFactoryBean(final FactoryBean factoryBean) {
    return factoryBean.getObjectType();
}

protected FactoryBean getFactoryBean(String beanName, Object beanInstance) throws BeansException {
    if (!(beanInstance instanceof FactoryBean)) {
        throw new BeanCreationException(beanName,
                "Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
    }
    return (FactoryBean) beanInstance;
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

你可能感兴趣的:(Spring IOC(四)FactoryBean)