zoukankan      html  css  js  c++  java
  • Spring IOC(四)FactoryBean

    Spring IOC(四)FactoryBean

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

    SingletonBeanRegistry 类图

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

    public interface FactoryBean<T> {
        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<Car> {
        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 后,就可以在配置文件中使用下面这种自定义的配置方式配置了

    <bean id="car" class="spring.factory_bean.CarFactoryBean">
        <property name="carInfo" value="红旗CA72,200,20000.00"/>
    </bean>
    

    当调用 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<String, Object> 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;
    }
    

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

  • 相关阅读:
    vagrant创建centos7后虚拟机磁盘爆满
    Linuxpython删除某个目录文件夹及文件的方法
    Oracle 中常用查询用户、角色、权限等SQL
    log4j2 rce几个疑惑点解惑
    2021年总结和反思
    使用grep命令,玩转代码审计寻找Sink
    VSCode使用技巧
    [转载]什么是电源的纹波,如何测量它的值,又如何抑制呢?
    【Bug system】GCC Bugzilla
    .net core3.1开始页面实时编译
  • 原文地址:https://www.cnblogs.com/binarylei/p/10316939.html
Copyright © 2011-2022 走看看