美文网首页
spring的factoryBean原理

spring的factoryBean原理

作者: hello_kd | 来源:发表于2020-10-25 12:00 被阅读0次

    spring容器管理的bean中,有一种比较特殊的类型FactoryBean,这种类型的bean,自身即是一个bean对象,也能产生其他类型的bean对象,通过接口方法便可得知

    //从工厂拿到bean对象
    T getObject() throws Exception
    //工厂产生bean的类型
    Class<?> getObjectType()
    //是否为单例的
    default boolean isSingleton() {
            return true;
        }
    

    为何需要FactoryBean来产生bean对象,而不是直接定义好呢,这个主要是在一些特殊的场景,比如bean对象的产生过程比较复杂,需要根据一些配置信息等等。

    如何从容器中获取一个bean对象?这是spring容器内部的一个实现逻辑,其中主要有三个变量要注意区分

    • name,外部要获取bean对象传入的名称
    • beanName,spring容器内部维护的bean对应的beanName,通常情况下name与beanName是一样的,除了FactoryBean的情况
    • shareInstance ,beanName对应的bean实例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
    //这里主要是为了处理FactoryBean的场景
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    

    普通的bean,根据beanName获取到的shareInstance对象就是最终要返回的对象,而FactoryBean就不太一样了
    例如:程序中定义了一个User对象,还有一个UserFactoryBean,User对象没有注入到spring容器,UserFactoryBean注入了,然后UserFactoryBean的工厂方法getObject返回的是一个User对象。
    那么,如果通过spring容器要获取到UserFactoryBean自身的bean实例,传入的name是&userFactoryBean,要获取User的bean实例,传入的name是userFactoryBean,若name传的是user,那么会找不到bean对象,这个也很好理解,User是通过UserFactoryBean产生的,所以传入userFactoryBean。

    接下来看下spring源码是如何处理这种情况的

    protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
        //根据name判断要获取的bean是FactoryBean自身,还是其工厂方法产生的,判断的依据就是name是否有&前缀
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (beanInstance instanceof NullBean) {
                return beanInstance;
            }
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
            }
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }
    
        //假如beanInstance自身就是一个普通的bean对象,那么直接返回
        if (!(beanInstance instanceof FactoryBean)) {
            return beanInstance;
        }
    
        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        else {
    //根据beanName获取缓存中工厂方法产生的对象
            object = getCachedObjectForFactoryBean(beanName);
        }
        if (object == null) {
            FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
            if (mbd == null && containsBeanDefinition(beanName)) {
                mbd = getMergedLocalBeanDefinition(beanName);
            }
            boolean synthetic = (mbd != null && mbd.isSynthetic());
    //获取工厂方法产生的bean对象,若是Singleton的,那么还会将对象缓存起来
            object = getObjectFromFactoryBean(factory, beanName, !synthetic);
        }
        return object;
    }
    

    这个方法逻辑很简单,如果beanInstance是普通的bean,那么直接返回;如果是FactoryBean的话,那么根据name判断程序是要获取FactoryBean自身的bean实例,还是其工厂方法产生的bean实例。若是自身的,那么直接返回;若是要获取工厂产生的,那么先看缓存有没,有的话直接拿,没有的话,再进入工厂方法创建bean。

    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)
                    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 {
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", 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;
        }
    }
    

    这个方法不仅仅是执行工厂方法,有几个点要注意

    1. 调用完工厂方法拿到对象后,并不是直接返回,还会调用BeanPostProcessor的postProcessAfterInitialization方法。spring内置的几个processor要执行
    2. 会判断工厂产生的bean是否为singleton,若是的话,还会加入到factoryBeanObjectCache,这样每次获取到的bean就是单例的,不会重新走工厂方法来创建一个新对象。

    以上就是从spring容器中获取FactoryBean和其工厂产生的bean的逻辑,细心的可能会发现,程序中有时并不是根据name来获取bean,而是通过Class对象,那么如果通过class对象来获取bean是如何处理的,跟踪源码会发现,也是需要根据Class类型获取到对应的name,再走上述讲的逻辑。所以重点就看下如果通过Class获取到name

    private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
        List<String> result = new ArrayList<>();
    
        // Check all bean definitions.
        for (String beanName : this.beanDefinitionNames) {
            // Only consider bean as eligible if the bean name is not defined as alias for some other bean.
            if (!isAlias(beanName)) {
                try {
                    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    // Only check bean definition if it is complete.
                    if (!mbd.isAbstract() && (allowEagerInit ||
                            (mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading()) &&
                                    !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                        boolean isFactoryBean = isFactoryBean(beanName, mbd);
                        BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                        boolean matchFound = false;
                        boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
                        boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
                        if (!isFactoryBean) {
                            if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
                                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                            }
                        }
                        else {
                            if (includeNonSingletons || isNonLazyDecorated ||
                                    (allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
                                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                            }
                            if (!matchFound) {
                                // In case of FactoryBean, try to match FactoryBean instance itself next.
                                beanName = FACTORY_BEAN_PREFIX + beanName;
                                matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
                            }
                        }
                        if (matchFound) {
                            result.add(beanName);
                        }
                    }
                }
                catch (CannotLoadBeanClassException | BeanDefinitionStoreException ex) {
                    
                }
                catch (NoSuchBeanDefinitionException ex) {
                
                }
            }
        }
            //省略.......
        return StringUtils.toStringArray(result);
    }
    

    这个方法的主要逻辑就是,循环spring容器的所有beanName,然后再根据isTypeMatch方法来判断当前的Class类型是否能匹配上这个beanName,若是的话,会返回。
    这里不管当前beanName对应的bean是否为FactoryBean,都走的是isTypeMatch方法。所以问题的关键就在这方法内部,但是会发现如果isFactoryBean是true的话,可能需要执行两次isTypeMatch,这结合isTypeMatch方法逻辑便可知道了

        protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
                throws NoSuchBeanDefinitionException {
    
            String beanName = transformedBeanName(name);
            boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
    
            // Check manually registered singletons.
            Object beanInstance = getSingleton(beanName, false);
            if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
                if (beanInstance instanceof FactoryBean) {
                    if (!isFactoryDereference) {
                        Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
                        return (type != null && typeToMatch.isAssignableFrom(type));
                    }
                    else {
                        return typeToMatch.isInstance(beanInstance);
                    }
                }
                else if (!isFactoryDereference) {
                    if (typeToMatch.isInstance(beanInstance)) {
                        // Direct match for exposed instance?
                        return true;
                    }
    

    这个方法比较长,只挑前面一部分代码就可以大概的理解逻辑了
    根据beanName获取到bean对象,如果bean对象只是普通类型的,那么就直接对比对象是否为ResolvableType 的,若是则匹配成功(实际会复杂一些)
    若bean对象是FactoryBean的,那么根据传进来的name是否要获取FactoryBean自身的,若是的话,也是直接比较(和普通类型的一样)。若不是,说明要获取的是工厂方法产生的bean,那么需要调用FactoryBean的getObjectType方法,来判断工厂返回的类型能否匹配上ResolvableType

    相关文章

      网友评论

          本文标题:spring的factoryBean原理

          本文链接:https://www.haomeiwen.com/subject/jnpotctx.html